Skip to content

Commit fbbec14

Browse files
authored
Merge pull request #8138 from marmelab/fix-formstate-update
Fix ensure react-hook-form `formState` update is always enable
2 parents 44b52e4 + 3f097c1 commit fbbec14

File tree

3 files changed

+65
-3
lines changed

3 files changed

+65
-3
lines changed

packages/ra-core/src/controller/input/useReferenceInputController.spec.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ describe('useReferenceInputController', () => {
165165
);
166166

167167
await waitFor(() => {
168-
expect(children).toBeCalledTimes(3);
168+
expect(children).toBeCalledTimes(4);
169169
});
170170
expect(children).toHaveBeenCalledWith(
171171
expect.objectContaining({

packages/ra-core/src/form/Form.spec.tsx

+26-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { fireEvent, screen, render, waitFor } from '@testing-library/react';
3-
import { useFormState } from 'react-hook-form';
3+
import { useFormState, useFormContext } from 'react-hook-form';
44
import { yupResolver } from '@hookform/resolvers/yup';
55
import * as yup from 'yup';
66

@@ -10,6 +10,7 @@ import { Form } from './Form';
1010
import { useNotificationContext } from '../notification';
1111
import { useInput } from './useInput';
1212
import { required } from './validate';
13+
import assert from 'assert';
1314

1415
describe('Form', () => {
1516
const Input = props => {
@@ -106,6 +107,30 @@ describe('Form', () => {
106107
expect(screen.getByText('isDirty: false')).not.toBeNull();
107108
});
108109

110+
it('should update Form state on submit', async () => {
111+
let globalFormState;
112+
113+
const CustomInput = props => {
114+
globalFormState = useFormContext();
115+
116+
return <Input {...props} />;
117+
};
118+
render(
119+
<CoreAdminContext>
120+
<Form onSubmit={jest.fn()}>
121+
<CustomInput source="name" validate={required()} />
122+
<button type="submit">Submit</button>
123+
</Form>
124+
</CoreAdminContext>
125+
);
126+
127+
fireEvent.click(screen.getByText('Submit'));
128+
129+
await waitFor(() => {
130+
assert.equal(globalFormState.formState.isSubmitting, true);
131+
});
132+
});
133+
109134
it('Displays a notification on submit when invalid', async () => {
110135
const Notification = () => {
111136
const { notifications } = useNotificationContext();

packages/ra-core/src/form/useAugmentedForm.ts

+38-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,17 @@ export const useAugmentedForm = (props: UseAugmentedFormProps) => {
4545

4646
const defaultValuesIncludingRecord = useMemo(
4747
() => getFormInitialValues(defaultValues, record),
48-
[JSON.stringify({ defaultValues: typeof defaultValues === 'function' ? 'function' : defaultValues, record })] // eslint-disable-line
48+
// eslint-disable-next-line
49+
[
50+
// eslint-disable-next-line
51+
JSON.stringify({
52+
defaultValues:
53+
typeof defaultValues === 'function'
54+
? 'function'
55+
: defaultValues,
56+
record,
57+
}),
58+
]
4959
);
5060

5161
const finalResolver = resolver
@@ -67,6 +77,33 @@ export const useAugmentedForm = (props: UseAugmentedFormProps) => {
6777
shouldUseNativeValidation,
6878
});
6979

80+
// According to react-hook-form docs: https://react-hook-form.com/api/useform/formstate
81+
// `formState` must be read before a render in order to enable the state update.
82+
const {
83+
formState: {
84+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
85+
isSubmitting,
86+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
87+
isDirty,
88+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
89+
isValid,
90+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
91+
isValidating,
92+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
93+
dirtyFields,
94+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
95+
errors,
96+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
97+
submitCount,
98+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
99+
touchedFields,
100+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
101+
isSubmitted,
102+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
103+
isSubmitSuccessful,
104+
},
105+
} = form;
106+
70107
// initialize form with record
71108
/* eslint-disable react-hooks/exhaustive-deps */
72109
useEffect(() => {

0 commit comments

Comments
 (0)