Composing forms when formOptions defaultValues is dynamic #2026
Replies: 1 comment
-
|
A few patterns work here, depending on your constraints: Pattern 1: Gate rendering until data arrives (my default for edit forms) Keep // shared/entityFormOptions.ts
export const entityFormOptions = formOptions({
defaultValues: { name: '', description: '' },
validators: { onChange: entitySchema },
});
// EditPage.tsx
const { data, isLoading } = useQuery({ queryKey: ['entity', id], queryFn: fetchEntity });
if (isLoading) return <Spinner />;
return <EditForm initialData={data} />;
// EditForm.tsx
function EditForm({ initialData }: { initialData: Entity }) {
const form = useAppForm({
...entityFormOptions,
defaultValues: initialData,
});
}Form state initializes once with real data, no reset dance, Pattern 2: const form = useAppForm({ ...entityFormOptions });
const { data } = useQuery({ queryKey: ['entity', id], queryFn: fetchEntity });
useEffect(() => {
if (data) form.reset({ values: data });
}, [data]);Fine, but you briefly render with empty values and then flip — touched state can get weird. Pattern 3: Factory function (clean when child forms genuinely need parent-derived defaults) export const createEntityFormOptions = (initialData: Partial<Entity> = {}) =>
formOptions({
defaultValues: { name: '', description: '', ...initialData },
validators: { onChange: entitySchema },
});
const { data } = useQuery({ ... });
const opts = useMemo(() => createEntityFormOptions(data), [data]);
if (!data) return null;
return <EntityForm formOptions={opts} />;In most edit-form cases Pattern 1 has been the least surprising — the form options stay trivially sharable and you skip both the reset call and the useMemo factory. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I'm having trouble figuring out a clean way to compose forms spread across multiple files / components when the formOptions are "dynamic". For instance, an entity is loaded from the server and its values are used as the "defaultValues" for formOptions. In the examples of form composition, formOptions is always declared in some "shared options" file and exported. Things get complicated if some of the form options are dynamic.
A few options I've explored so far:
useTypedAppFormContextformOptionseverywhere. Not pretty - there's like 12 generic types onFormOptions...formOptions+useTypedAppFormContextwithForm. A bit clunky. Doesn't work well if the formOptions from parent + child differ even slightlyWondering how others have approached this problem.
Beta Was this translation helpful? Give feedback.
All reactions