T
TanStack5w ago
harsh-harlequin

useStore vs withForm

Hey Guys, im really new to tanstack/form and i have a question regarding the usage of withForm. I am currently refactoring a feature where I fetch a set of data from my backend and the user can change fields of the fetched data with inputs. Currently it is one big useState and the onChange and the mutableDataObject is prop-drilled down to every component that needs to change the data. It is a multi-step "form". Really just fields on a Page the user can edit. Now to my question. If i wrap the whole page with my form and all steps are only conditionally rendered. What is the benefit of using withForm? I still need to prop drill the form instance to each component with or without the withForm HOC. Most of my Components currently need the whole dataObject to determine if it should render. I am currently getting the data from the useStore of the form and then rendering the fields as normal. All i really need would be a hook to get my current form via an id to not prop-drill it. The docs only specify to use withForm to break big forms into smaller pieces. Note for the screenshots: complexRisk is my fetched data and currentRisk is the mutable local data for the user
No description
No description
No description
5 Replies
generous-apricot
generous-apricot5w ago
withForm is intended for you to split up a huge form into smaller sections across multiple files. It's a HOC to type the form prop it accepts properly. It is unrelated to reducing prop drilling. Passing form through context sounds good on the surface, but it really lacks type safety since you just assume where the data comes from. There are cases where you have no choice but to do this, so we'll add a typed way to use it soon. However, for now, using the typed prop is the recommended way to go The structure of yours would likely be inverted with withForms: Each withForm is always rendered, but inside each one, it decides whether it is currently the right step. If not, then it returns null.
harsh-harlequin
harsh-harlequinOP5w ago
Thanks for the reply! My steps are currently all in different files. The form I give my ‚AdvancedRiskIdentification‘ is already typed, because I set the type in the ‚IAdvacedRiskIdentification‘ Interface. This would then be not necessary. But that would be my only benefit of the HOC? Also the currentStep is not managed by the form but by the page for rendering purposes.
generous-apricot
generous-apricot5w ago
Component rendering behaviour aside, yes that would be the only change while keeping the features. What is the type of your IAdvancedRiskIdentification currently?
harsh-harlequin
harsh-harlequinOP5w ago
This is how i typed it
No description
No description
generous-apricot
generous-apricot5w ago
yeah, so the typing would work differently with withForm. It could look something like this:
export const riskFormOptions = formOptions({
// defaultValues, revalidationLogic, validators
})

// Main
const form = useAppForm({
...riskFormOptions,
// if you have async or different values
defaultValues: myAsyncData ?? riskFormOptions.defaultValues,
onSubmit: () => {}
})

<AdvancedRiskIdentification form={form} />

// Step1
export const AdvancedRiskIdentification = withForm({
...riskFormOptions,
// TypeScript doesn't allow partial generics, but these values aren't used at runtime.
// feel free to assert here
props: {} as YourAdditionalProps
render: function Render({ form, currentStage, onAdvance }) {
// ...
}
})
export const riskFormOptions = formOptions({
// defaultValues, revalidationLogic, validators
})

// Main
const form = useAppForm({
...riskFormOptions,
// if you have async or different values
defaultValues: myAsyncData ?? riskFormOptions.defaultValues,
onSubmit: () => {}
})

<AdvancedRiskIdentification form={form} />

// Step1
export const AdvancedRiskIdentification = withForm({
...riskFormOptions,
// TypeScript doesn't allow partial generics, but these values aren't used at runtime.
// feel free to assert here
props: {} as YourAdditionalProps
render: function Render({ form, currentStage, onAdvance }) {
// ...
}
})
One benefit you would get this way is that onSubmit can be inside the component where you can leverage query libraries

Did you find this page helpful?