form icon indicating copy to clipboard operation
form copied to clipboard

When you render `Field` conditionally first rendered field will override all next rendered fields

Open vara855 opened this issue 1 year ago • 3 comments

Describe the bug

Use case:

I want to render different Field components according to some condition of form state.values.

It used to work in previous versions (0.21=<).

Your minimal, reproducible example

https://stackblitz.com/edit/vitejs-vite-dvwuju?file=src%2FApp.jsx

Steps to reproduce

  1. go to https://stackblitz.com/edit/vitejs-vite-dvwuju?file=src%2FApp.jsx
  2. fill input
  3. click checkbox
  4. check values of form

Expected behavior

I expected that values firstField value will dissapear from state when you uncheck checkbox and secondField value will be stored in state.

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

Arc browser

TanStack Form adapter

react-form

TanStack Form version

v0.25.1

TypeScript version

=v5.4.5

Additional context

No response

vara855 avatar Jul 02 '24 08:07 vara855

upd: You may fix it if you render it under different Subscribe components. But it feels like a bug...

vara855 avatar Jul 02 '24 09:07 vara855

You can also "fix" it by applying a key prop to each of the <Field> instances that would occupy the same position in the tree, (e.g. <Field key="first" name="firstField">).

Because of that, I think the problem is that the <Field> component and useField state not "noticing" when the name prop has changed.

Here, we see that the fieldApi instance is created once with the initial name value, and then kept in state.

https://github.com/TanStack/form/blob/2bebfd5214c4cdfbf6feacb7b1e25a6825957062/packages/react-form/src/useField.tsx#L68-L81

The value of this.name is only set when a new instance is constructed:

https://github.com/TanStack/form/blob/2bebfd5214c4cdfbf6feacb7b1e25a6825957062/packages/form-core/src/FieldApi.ts#L429-L442

And the field's getValue and setValue functions use the initial this.name value:

https://github.com/TanStack/form/blob/2bebfd5214c4cdfbf6feacb7b1e25a6825957062/packages/form-core/src/FieldApi.ts#L597-L611

In the update function, we can see that it uses the opt.name value to get the correct default value, but doesn't update the stored this.name to be the new value of opts.name; so getValue/setValue continue to use the (initial, now incorrect) value.

https://github.com/TanStack/form/blob/2bebfd5214c4cdfbf6feacb7b1e25a6825957062/packages/form-core/src/FieldApi.ts#L564-L595

BenJenkinson avatar Jul 15 '24 11:07 BenJenkinson

@BenJenkinson Yep, everything works as you explained. Thank you for explanation. I haven't tried to dive into implementation. In my codebase I've fixed it with two Subscribe blocks.

For me it looks like unhandled name property of opts in update.

I think it's worth fixing that. I may do a PR on that. Either it's worth reflecting in the doc. @crutchcorn what do you think? Do you mind if I fix it?

vara855 avatar Jul 20 '24 17:07 vara855

This issue should be fixed by https://github.com/TanStack/form/pull/1097#.

See the fixed reproducible example here: https://stackblitz.com/edit/vitejs-vite-y5jdu3qf?file=src%2FApp.jsx

fulopkovacs avatar Jan 11 '25 12:01 fulopkovacs