Ant Design Form failing to sync with asynchronous initialValues
0 reputation · 05 Apr 2021, 05:41 UTC
0 reputation · 05 Apr 2021, 05:41 UTC
The Ant Design Form component typically relies on the initialValues prop to populate fields during initialization. However, when data is fetched via an asynchronous operation, a race condition often occurs if the promise resolves after the Form component has already mounted.
In these scenarios, the internal FormInstance may remain empty or reflect the initial state despite the new data being passed to the prop. While setFieldsValue is often suggested as a manual workaround, it introduces risks of unnecessary render loops or state inconsistencies if not integrated precisely with the component lifecycle.
Does the Form component programmatically trigger a re-evaluation of initialValues if they change post-mount? What is the recommended pattern to ensure the internal store synchronizes with dynamic data without manually bypassing the declarative prop logic?
34775 reputation · 05 Apr 2021, 06:55 UTC
No. Ant Design's Form consumes initialValues only at mount time. Changing the prop after the Form has mounted does not re-evaluate it or update the internal store. This is intentional, documented behavior — not a race-condition bug. If the prop were reactive, every re-render with new data would silently overwrite the user's in-progress edits.
The officially supported way to sync async data is to get the form instance via Form.useForm() and push the fetched values in a useEffect:
const [form] = Form.useForm();
const { data } = useQuery(['user', id], fetchUser);
useEffect(() => {
if (data) {
form.setFieldsValue(data);
}
}, [data, form]);
return (
<Form form={form} onFinish={onSubmit}>
<Form.Item name="email" label="Email"><Input /></Form.Item>
</Form>
);Two facts clear up the common fears about this approach:
setFieldsValue only writes to the store. It does not trigger validation or onValuesChange, and it does not cause render loops by itself. Loops only happen when the effect's dependencies are unstable — for example, depending on an object literal recreated every render. Depend on the query result or a stable identifier, not on inline objects.setFieldsValue during render — only in an effect or event handler.If you need the injected values validated, call form.validateFields() explicitly afterward.
If you'd rather stay purely declarative, make the mount coincide with data availability so initialValues is applied fresh:
{data && <Form initialValues={data}>...</Form>}
{/* or force a remount when the record changes */}
<Form key={data?.id ?? 'loading'} initialValues={data}>...</Form>The trade-off: a remount discards all form state (touched flags, errors, unsaved edits), so it fits "load once, then edit" screens but not forms that receive updates while the user is typing.
form.setFieldValue(name, value); v4 has only setFieldsValue. Check your package.json before relying on the singular form.preserve is configured on the Form or Form.Item.setFieldsValue with a subset of fields leaves the rest untouched.initialValues, then resolve async data into the prop — confirm the fields stay empty, proving the prop is mount-only.useEffect calling setFieldsValue and confirm it runs once per data change, not in a loop.key={data.id} and confirming fields populate on arrival.One caveat: exact defaults for preserve and the availability of setFieldValue vary across antd 4.x/5.x minor releases, so confirm against your installed version's docs.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.