Skip to content

Commit d135bd3

Browse files
authored
Merge pull request #10417 from marmelab/fix-form-data-consumer-flicker
Fix form data consumer flicker
2 parents 526d088 + b05a1a0 commit d135bd3

File tree

2 files changed

+112
-12
lines changed

2 files changed

+112
-12
lines changed

packages/ra-core/src/form/FormDataConsumer.tsx

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { useFormContext, FieldValues } from 'react-hook-form';
44
import get from 'lodash/get';
55
import { useFormValues } from './useFormValues';
66
import { useWrappedSource } from '../core';
7+
import { useEvent } from '../util';
78

89
/**
910
* Get the current (edited) value of the record from the form and pass it
@@ -67,22 +68,26 @@ export const FormDataConsumerView = <
6768
props: Props<TFieldValues>
6869
) => {
6970
const { children, formData, source } = props;
70-
let ret;
71+
const [result, setResult] = React.useState<ReactNode>(null);
7172

7273
const finalSource = useWrappedSource(source || '');
74+
const render = useEvent(children);
7375

74-
// Passes an empty string here as we don't have the children sources and we just want to know if we are in an iterator
75-
const matches = ArraySourceRegex.exec(finalSource);
76+
// Getting the result of the children function in a useEffect allows us to keep a stable reference to is
77+
// with useEvent
78+
React.useEffect(() => {
79+
// Passes an empty string here as we don't have the children sources and we just want to know if we are in an iterator
80+
const matches = ArraySourceRegex.exec(finalSource);
81+
// If we have an index, we are in an iterator like component (such as the SimpleFormIterator)
82+
if (matches) {
83+
const scopedFormData = get(formData, matches[0]);
84+
setResult(render({ formData, scopedFormData }));
85+
} else {
86+
setResult(render({ formData }));
87+
}
88+
}, [finalSource, formData, render]);
7689

77-
// If we have an index, we are in an iterator like component (such as the SimpleFormIterator)
78-
if (matches) {
79-
const scopedFormData = get(formData, matches[0]);
80-
ret = children({ formData, scopedFormData });
81-
} else {
82-
ret = children({ formData });
83-
}
84-
85-
return ret === undefined ? null : ret;
90+
return result;
8691
};
8792

8893
const ArraySourceRegex = new RegExp(/.+\.\d+$/);
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import * as React from 'react';
2+
import { FormDataConsumer, required, ResourceContextProvider } from 'ra-core';
3+
import fakeRestDataProvider from 'ra-data-fakerest';
4+
import { AdminContext } from '../AdminContext';
5+
import { AutocompleteInput, ReferenceInput, TextInput } from '../input';
6+
import { SimpleForm } from './SimpleForm';
7+
import { Create } from '../detail';
8+
9+
// We keep this test in ra-ui-materialui because we need heavy components to reproduce the issue https://github.com/marmelab/react-admin/issues/10415
10+
export default { title: 'ra-core/form/FormDataConsumer' };
11+
12+
export const Basic = () => (
13+
<AdminContext dataProvider={dataProvider}>
14+
<ResourceContextProvider value="posts">
15+
<Create>
16+
<SimpleForm>
17+
<TextInput source="title" />
18+
<FormDataConsumer<any>>
19+
{({ formData }) => {
20+
console.log({ formData });
21+
if (!formData.title) {
22+
return null;
23+
}
24+
return (
25+
<ReferenceInput
26+
source="userId"
27+
reference="users"
28+
>
29+
<AutocompleteInput
30+
shouldUnregister
31+
label="User"
32+
optionText={choice =>
33+
`${choice.name} / (${choice.id})`
34+
}
35+
noOptionsText="User doesn't exist"
36+
isRequired
37+
validate={[
38+
required('User is required.'),
39+
]}
40+
/>
41+
</ReferenceInput>
42+
);
43+
}}
44+
</FormDataConsumer>
45+
<TextInput source="body" multiline rows={5} />
46+
</SimpleForm>
47+
</Create>
48+
</ResourceContextProvider>
49+
</AdminContext>
50+
);
51+
52+
const dataProvider = fakeRestDataProvider({
53+
users: [
54+
{
55+
id: 1,
56+
name: 'Leanne Graham',
57+
},
58+
{
59+
id: 2,
60+
name: 'Ervin Howell',
61+
},
62+
{
63+
id: 3,
64+
name: 'Clementine Bauch',
65+
},
66+
{
67+
id: 4,
68+
name: 'Patricia Lebsack',
69+
},
70+
{
71+
id: 5,
72+
name: 'Chelsey Dietrich',
73+
},
74+
{
75+
id: 6,
76+
name: 'Mrs. Dennis Schulist',
77+
},
78+
{
79+
id: 7,
80+
name: 'Kurtis Weissnat',
81+
},
82+
{
83+
id: 8,
84+
name: 'Nicholas Runolfsdottir V',
85+
},
86+
{
87+
id: 9,
88+
name: 'Glenna Reichert',
89+
},
90+
{
91+
id: 10,
92+
name: 'Clementina DuBuque',
93+
},
94+
],
95+
});

0 commit comments

Comments
 (0)