T
TanStack8mo ago
continuing-cyan

Incorrect type for field.state.meta.errors?

When my form first renders, field.state.meta.errors is undefined when the Typescript type argues it is always an array. I have a simple form with two fields which are validated with zod.
const productSchema = z.object({
name: z.string().min(1, "A name is required"),
allowance: z
.number()
.min(1, "Allowance must be at least 1")
.int("Allowance must be an integer"),
});

const form = useForm({
defaultValues: {
name: "Dataset Storage",
allowance: 1000,
},
validators: {
onChange: productSchema,
},
})
const productSchema = z.object({
name: z.string().min(1, "A name is required"),
allowance: z
.number()
.min(1, "Allowance must be at least 1")
.int("Allowance must be an integer"),
});

const form = useForm({
defaultValues: {
name: "Dataset Storage",
allowance: 1000,
},
validators: {
onChange: productSchema,
},
})
Then the react component
<form.Field name="name">
{(field) => (
<TextField
autoFocus
error={field.state.meta.errors.length > 0}
helperText={field.state.meta.errors.map((error) => error?.message)[0]}
label="Name"
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
)}
</form.Field>
<form.Field name="name">
{(field) => (
<TextField
autoFocus
error={field.state.meta.errors.length > 0}
helperText={field.state.meta.errors.map((error) => error?.message)[0]}
label="Name"
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
)}
</form.Field>
errors on both the errors and helperText props because I'm accessing on undefined.
Unhandled Runtime Error

TypeError: field.state.meta.errors is undefined
Unhandled Runtime Error

TypeError: field.state.meta.errors is undefined
Yet, Typescript argues it's an array. What's going on with the tanstack/form types here?
6 Replies
rising-crimson
rising-crimson8mo ago
Seems like you need to use the store here to get the errors in a reactive way, otherwise they might be stale.
const errors = useStore(field.store, (state) => state.meta.errors);
const errors = useStore(field.store, (state) => state.meta.errors);
other-emerald
other-emerald8mo ago
not sure if the reactivity is the issue here, but likely something with the first mount. Can you reproduce this issue on stackblitz? I usually see this undefined stuff when accessing from form.fieldInfo directly, but this is the first time I see it happen from a field
continuing-cyan
continuing-cyanOP8mo ago
Hmm this is very weird. The component with the useForm mounts when the user selects a value in a select component. This component appears in two places in the app. It's the same component and Jotai is used to handle the state. When the select component close to the form changes, the form renders without error. When I use the other select, this error appears.
continuing-cyan
continuing-cyanOP8mo ago
Ok managed to put together a repro. https://stackblitz.com/edit/vitejs-vite-nuuv84ts?file=src%2FApp.tsx This matches my setup well though. Two ways to make the form mount: 1. A button that lies next to the form component wrapper (works normally) 2. A button that lives in a diaglog (causes an error) (Refresh the page between each button option) Each button changes state managed by Jotai which leads to the conditional render of the Form.
Oliver Dudgeon
StackBlitz
Vitejs - Vite (forked) - StackBlitz
Next generation frontend tooling. It's fast!
other-emerald
other-emerald8mo ago
how strange it's not the first mount that has the undefined error
No description
continuing-cyan
continuing-cyanOP7mo ago
So is the value changing on re-render or is the form unmounting and then remounting with a value of undefined? And any ideas of why the two flows lead to different results? Is it worth creating a GitHub issue for this?

Did you find this page helpful?