Skip to content

Commit 65f0e9b

Browse files
author
Erik Rasmussen
committed
Fix #1050: useField returns Form initialValues on first render
Issue: In v7.0.0, useField returns undefined on first render even when Form initialValues are set. This breaks apps trying to upgrade from v6. Root cause: useField's useState initializer falls back to creating initial state when getFieldState() returns undefined, but only checks field-level initialValue, not the Form's initialValues. Solution: In the fallback case, check form.getState().initialValues[name] before using field-level initialValue. Form-level initialValues take precedence. Tests: - useField returns Form initialValues on first render - useField uses field initialValue when Form initialValues missing that field - All existing tests pass (14/14) This is a clean solution that avoids the side effects of synchronous registration during render (which React forbids).
1 parent 0a1c4dc commit 65f0e9b

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

src/useField.test.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -508,4 +508,46 @@ describe("useField", () => {
508508
expect(calls).toContain("test"); // At least one call with 'test'
509509
expect(calls[calls.length - 1]).toBe(null); // Last call is null
510510
});
511+
512+
it("should return Form initialValues on first render (fix #1050)", () => {
513+
const renderSpy = jest.fn();
514+
const MyField = () => {
515+
const { input } = useField("username");
516+
renderSpy(input.value);
517+
return <input {...input} data-testid="username" />;
518+
};
519+
const { getByTestId } = render(
520+
<Form onSubmit={onSubmitMock} initialValues={{ username: "erikras" }}>
521+
{() => (
522+
<form>
523+
<MyField />
524+
</form>
525+
)}
526+
</Form>,
527+
);
528+
// Critical: on the FIRST render, value should be "erikras" not undefined
529+
expect(renderSpy.mock.calls[0][0]).toBe("erikras");
530+
expect(getByTestId("username").value).toBe("erikras");
531+
});
532+
533+
it("should use field initialValue when Form initialValues doesn't have that field (fix #1050)", () => {
534+
const renderSpy = jest.fn();
535+
const MyField = () => {
536+
const { input } = useField("username", { initialValue: "fieldLevel" });
537+
renderSpy(input.value);
538+
return <input {...input} data-testid="username" />;
539+
};
540+
const { getByTestId } = render(
541+
<Form onSubmit={onSubmitMock} initialValues={{ other: "value" }}>
542+
{() => (
543+
<form>
544+
<MyField />
545+
</form>
546+
)}
547+
</Form>,
548+
);
549+
// Field-level initialValue should be used as fallback
550+
expect(renderSpy.mock.calls[0][0]).toBe("fieldLevel");
551+
expect(getByTestId("username").value).toBe("fieldLevel");
552+
});
511553
});

src/useField.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,15 @@ function useField<
113113
return existingFieldState;
114114
}
115115

116+
// FIX #1050: Check Form initialValues before falling back to field initialValue
116117
// If no existing state, create a proper initial state
117-
let initialStateValue = initialValue;
118-
if (component === "select" && multiple && initialValue === undefined) {
118+
const formState = form.getState();
119+
const formInitialValue = formState.initialValues?.[name as keyof FormValues];
120+
121+
// Use Form initialValues if available, otherwise use field initialValue
122+
let initialStateValue = formInitialValue !== undefined ? formInitialValue : initialValue;
123+
124+
if (component === "select" && multiple && initialStateValue === undefined) {
119125
initialStateValue = [];
120126
}
121127

0 commit comments

Comments
 (0)