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.'),
+ ]}
+ />
+
+ );
}}