Skip to content

Commit 92187d3

Browse files
juanvilladevHarry Whorlow
authored andcommitted
fix(form-core): move setting default value to mount function to avoid react set state on render error + include test in react package
1 parent 7d15cdb commit 92187d3

File tree

2 files changed

+53
-6
lines changed

2 files changed

+53
-6
lines changed

packages/form-core/src/FieldApi.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -997,11 +997,6 @@ export class FieldApi<
997997
this.form = opts.form as never
998998
this.name = opts.name as never
999999
this.timeoutIds = {} as Record<ValidationCause, never>
1000-
if (opts.defaultValue !== undefined) {
1001-
this.form.setFieldValue(this.name, opts.defaultValue as never, {
1002-
dontUpdateMeta: true,
1003-
})
1004-
}
10051000

10061001
this.store = new Derived({
10071002
deps: [this.form.store],
@@ -1072,6 +1067,12 @@ export class FieldApi<
10721067
mount = () => {
10731068
const cleanup = this.store.mount()
10741069

1070+
if (this.options.defaultValue !== undefined) {
1071+
this.form.setFieldValue(this.name, this.options.defaultValue as never, {
1072+
dontUpdateMeta: true,
1073+
})
1074+
}
1075+
10751076
const info = this.getInfo()
10761077
info.instance = this as never
10771078

@@ -1553,7 +1554,6 @@ export class FieldApi<
15531554

15541555
// TODO: Dedupe this logic to reduce bundle size
15551556
for (const validateObj of validates) {
1556-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
15571557
if (!validateObj.validate) continue
15581558
validateFieldAsyncFn(this, validateObj, validatesPromises)
15591559
}

packages/react-form/tests/useField.test.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,4 +1130,51 @@ describe('useField', () => {
11301130
// field2 should not have rerendered
11311131
expect(renderCount.field2).toBe(field2InitialRender)
11321132
})
1133+
1134+
it('should handle defaultValue without setstate-in-render error', async () => {
1135+
// Spy on console.error before rendering
1136+
const consoleErrorSpy = vi.spyOn(console, 'error')
1137+
1138+
function Comp() {
1139+
const form = useForm({
1140+
defaultValues: {
1141+
fieldOne: '',
1142+
fieldTwo: '',
1143+
},
1144+
})
1145+
1146+
const fieldOne = useStore(form.store, (state) => state.values.fieldOne)
1147+
1148+
return (
1149+
<form>
1150+
<form.Field
1151+
name="fieldOne"
1152+
children={(field) => {
1153+
return (
1154+
<input
1155+
data-testid={field.name}
1156+
id={field.name}
1157+
value={field.state.value}
1158+
onChange={(e) => field.handleChange(e.target.value)}
1159+
/>
1160+
)
1161+
}}
1162+
/>
1163+
{fieldOne && (
1164+
<form.Field
1165+
name="fieldTwo"
1166+
defaultValue="default field two value"
1167+
children={(_) => null}
1168+
/>
1169+
)}
1170+
</form>
1171+
)
1172+
}
1173+
1174+
const { getByTestId } = render(<Comp />)
1175+
await user.type(getByTestId('fieldOne'), 'John')
1176+
1177+
// Should not log an error
1178+
expect(consoleErrorSpy).not.toHaveBeenCalled()
1179+
})
11331180
})

0 commit comments

Comments
 (0)