From fa523be93a353d70709ad2fe53a8fcb98c035878 Mon Sep 17 00:00:00 2001 From: Gildas <1122076+djhi@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:20:17 +0100 Subject: [PATCH 1/4] Add a FormDataConsumer showing the issue --- .../src/form/FormDataConsumer.stories.tsx | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx diff --git a/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx b/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx new file mode 100644 index 0000000000..8a0f83ce39 --- /dev/null +++ b/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx @@ -0,0 +1,94 @@ +import * as React from 'react'; +import { FormDataConsumer, required, ResourceContextProvider } from 'ra-core'; +import fakeRestDataProvider from 'ra-data-fakerest'; +import { AdminContext } from '../AdminContext'; +import { AutocompleteInput, ReferenceInput, TextInput } from '../input'; +import { SimpleForm } from './SimpleForm'; +import { Create } from '../detail'; + +export default { title: 'ra-core/form/FormDataConsumer' }; + +export const Basic = () => ( + + + + + + > + {({ formData }) => { + console.log({ formData }); + if (!!formData.title) { + return ( + + + `${choice.name} / (${choice.id})` + } + // optionValue="userId" + noOptionsText="User does'nt exist" + isRequired + validate={[ + required('User is Required.'), + ]} + /> + + ); + } else return null; + }} + + + + + + +); + +const dataProvider = fakeRestDataProvider({ + users: [ + { + id: 1, + name: 'Leanne Graham', + }, + { + id: 2, + name: 'Ervin Howell', + }, + { + id: 3, + name: 'Clementine Bauch', + }, + { + id: 4, + name: 'Patricia Lebsack', + }, + { + id: 5, + name: 'Chelsey Dietrich', + }, + { + id: 6, + name: 'Mrs. Dennis Schulist', + }, + { + id: 7, + name: 'Kurtis Weissnat', + }, + { + id: 8, + name: 'Nicholas Runolfsdottir V', + }, + { + id: 9, + name: 'Glenna Reichert', + }, + { + id: 10, + name: 'Clementina DuBuque', + }, + ], +}); From 08f256b0b7a2f9d954fb056070b51c7b0f6a54cc Mon Sep 17 00:00:00 2001 From: Gildas <1122076+djhi@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:23:28 +0100 Subject: [PATCH 2/4] Fix FormDataConsumer --- .../ra-core/src/form/FormDataConsumer.tsx | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/packages/ra-core/src/form/FormDataConsumer.tsx b/packages/ra-core/src/form/FormDataConsumer.tsx index 39205f7ec2..7659835765 100644 --- a/packages/ra-core/src/form/FormDataConsumer.tsx +++ b/packages/ra-core/src/form/FormDataConsumer.tsx @@ -4,6 +4,7 @@ import { useFormContext, FieldValues } from 'react-hook-form'; import get from 'lodash/get'; import { useFormValues } from './useFormValues'; import { useWrappedSource } from '../core'; +import { useEvent } from '../util'; /** * Get the current (edited) value of the record from the form and pass it @@ -67,22 +68,26 @@ export const FormDataConsumerView = < props: Props ) => { const { children, formData, source } = props; - let ret; + const [result, setResult] = React.useState(null); const finalSource = useWrappedSource(source || ''); + const render = useEvent(children); - // 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 - const matches = ArraySourceRegex.exec(finalSource); + // Getting the result of the children function in a useEffect allows us to keep a stable reference to is + // with useEvent + React.useEffect(() => { + // 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 + const matches = ArraySourceRegex.exec(finalSource); + // If we have an index, we are in an iterator like component (such as the SimpleFormIterator) + if (matches) { + const scopedFormData = get(formData, matches[0]); + setResult(render({ formData, scopedFormData })); + } else { + setResult(render({ formData })); + } + }, [finalSource, formData, render]); - // If we have an index, we are in an iterator like component (such as the SimpleFormIterator) - if (matches) { - const scopedFormData = get(formData, matches[0]); - ret = children({ formData, scopedFormData }); - } else { - ret = children({ formData }); - } - - return ret === undefined ? null : ret; + return result; }; const ArraySourceRegex = new RegExp(/.+\.\d+$/); From 5d339c84c84390e54fbeb8590759a197ab612586 Mon Sep 17 00:00:00 2001 From: Gildas <1122076+djhi@users.noreply.github.com> Date: Mon, 16 Dec 2024 17:30:46 +0100 Subject: [PATCH 3/4] Add comment [no ci] --- packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx b/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx index 8a0f83ce39..457d50857b 100644 --- a/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx +++ b/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx @@ -6,6 +6,7 @@ import { AutocompleteInput, ReferenceInput, TextInput } from '../input'; import { SimpleForm } from './SimpleForm'; import { Create } from '../detail'; +// 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 export default { title: 'ra-core/form/FormDataConsumer' }; export const Basic = () => ( From b05a1a0f960097b2bd8ab6f63a0faf88bdafb525 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Kaiser Date: Tue, 17 Dec 2024 09:56:32 +0100 Subject: [PATCH 4/4] [no ci] minor improvements to story --- .../src/form/FormDataConsumer.stories.tsx | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx b/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx index 457d50857b..e05cd50afe 100644 --- a/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx +++ b/packages/ra-ui-materialui/src/form/FormDataConsumer.stories.tsx @@ -18,28 +18,28 @@ export const Basic = () => ( > {({ formData }) => { console.log({ formData }); - if (!!formData.title) { - return ( - - - `${choice.name} / (${choice.id})` - } - // optionValue="userId" - noOptionsText="User does'nt exist" - isRequired - validate={[ - required('User is Required.'), - ]} - /> - - ); - } else return null; + if (!formData.title) { + return null; + } + return ( + + + `${choice.name} / (${choice.id})` + } + noOptionsText="User doesn't exist" + isRequired + validate={[ + required('User is required.'), + ]} + /> + + ); }}