T
TanStack3mo ago
useful-bronze

Not using index as key while looping values lead to `field.state.value is undefined` when deleting

Here is my minimal example of one of my complex forms in a project:
const formOpts = formOptions({
defaultValues: { values: [] as { id: number; value: string }[] },
});

function RouteComponent() {
const form = useAppForm({
...formOpts,
});

return (
<form.AppForm>
<button
onClick={() =>
form.pushFieldValue("values", {
id: Date.now(),
value: `Value - ${form.state.values.values.length}`,
})
}
>
Add
</button>

<Child form={form} />
</form.AppForm>
);
}

const Child = withForm({
...formOpts,
render: ({ form }) => {
const values = useStore(form.store, (store) => store.values.values);

return (
<>
{values.map(({ id }, index) => (
<li key={id}>
<GrandChild form={form} index={index} />
<button onClick={() => form.removeFieldValue("values", index)}>
Delete
</button>
</li>
))}
</>
);
},
});

const GrandChild = withForm({
...formOpts,
props: {} as { index: number },
render: ({ form, index }) => (
<form.AppField
name={`values[${index}]`}
children={(field) => <>{field.state.value.value}</>}
/>
),
});
const formOpts = formOptions({
defaultValues: { values: [] as { id: number; value: string }[] },
});

function RouteComponent() {
const form = useAppForm({
...formOpts,
});

return (
<form.AppForm>
<button
onClick={() =>
form.pushFieldValue("values", {
id: Date.now(),
value: `Value - ${form.state.values.values.length}`,
})
}
>
Add
</button>

<Child form={form} />
</form.AppForm>
);
}

const Child = withForm({
...formOpts,
render: ({ form }) => {
const values = useStore(form.store, (store) => store.values.values);

return (
<>
{values.map(({ id }, index) => (
<li key={id}>
<GrandChild form={form} index={index} />
<button onClick={() => form.removeFieldValue("values", index)}>
Delete
</button>
</li>
))}
</>
);
},
});

const GrandChild = withForm({
...formOpts,
props: {} as { index: number },
render: ({ form, index }) => (
<form.AppField
name={`values[${index}]`}
children={(field) => <>{field.state.value.value}</>}
/>
),
});
Here, when I delete any items except the last one using the delete button of Child component, then it causes leads to field.state.value is undefined error. If I change the key of li in Child component to index, then it works fine. I don't want to use index as keys for obvious reasons. Is there any way to fix this issue? Is there any other ways to do the same thing? If you are wondering why I am separating GrandChild component, then let's just say that my form is much complicated than this example. That's why I must separate the component.
1 Reply
metropolitan-bronze
metropolitan-bronze3mo ago
You are likely experiencing the same issue as listed here: https://github.com/TanStack/form/issues/1518 The behaviour appears to be the same. Note how the last element in the array can be removed no problem, just like the issue describes.
GitHub
Field value within a re-indexed parent array item (keyed by UUID) t...
Describe the bug In TanStack Form, when managing an array of objects where each object uses a unique React key (e.g., a uuid), a specific re-render issue can occur. If an item is removed from this ...

Did you find this page helpful?