Back to News & Insights
JavaScript August 27, 2026 · 4 min read

useFieldArray is not updating across steps — and why it can't

If you have a wizard where step two appends to items and step four also appends to items, and the two...

useFieldArray is not updating across steps — and why it can't

If you have a wizard where step two appends to items and step four also appends to items, and the two steps never see each other's data — you have not misconfigured anything. Two useFieldArray instances pointed at the same name cannot observe each other, by design. Each one keeps a private snapshot of that array internally.

No two useFieldArray for the same field can be instantiated, as each handles its own snapshot of state internally.

For a single-page form this never surfaces. For a wizard it surfaces on day one.

The reason react-hook-form is fast is that state lives close to the inputs and is not centralised. Inputs are uncontrolled, the form does not re-render on every keystroke, and each useFieldArray owns its slice. Sharing one array across mounting boundaries asks for the opposite architecture — a central store that every instance subscribes to.

That tension is real. It is why the request keeps reopening rather than getting fixed.

Multi-page forms. Different steps need to update the same field array, and there is no first-party way to share one instance across them.

Conditional fields inside an array item. Uncontrolled inputs do not re-render when a value changes, so showing or hiding a nested field based on a sibling's value simply does not react.

Arrays that mount and unmount. Toggled sections, wizard steps and tab navigation all remount the array — the scenario most likely to lose state in a way that looks like a bug in your own code.

For "show this field only when a sibling has a certain value", there is a clean first-party answer. Do not reach for watch() on the whole form: that re-renders everything and throws away the reason you picked this library.

Instead, extract the dependent field into its own component and subscribe to that one array item with useWatch:

The whole trick is the component boundary. useWatch re-renders the component that called it, so keeping that component tiny keeps the cost tiny. You get reactivity without giving up the uncontrolled model.

For the wizard case there is no first-party answer. The pattern that circulates — and the one that actually works — is to instantiate the field array once and hand it down through your own React context, so every step reads the same instance instead of creating a second one.

If the provider unmounts, the field array unmounts with it, and the second mount is a brand-new instance with a fresh snapshot. Which is the original bug, reintroduced by the fix.

It works. It is also a piece of state architecture you now own and maintain — in a library you adopted specifically so you would not have to.

I maintain a form orchestrator built on top of react-hook-form, so it would be a strange article to end with a pitch. Our own useDashFieldArray does not solve this either.

It is a thin adapter: it pre-computes the field path and exposes a live index, then delegates every operation straight through to RHF.

Better DX — you stop hand-building items.${index}.sku strings — but two instances on the same name behave exactly as RHF's do, because underneath they are RHF's. Fixing this properly means owning array state centrally, which is a different architecture, not a wrapper.

So the honest summary for today: Conditional fields inside an array → solved, use useWatch at the component level. One array shared across wizard steps → not solved upstream. Own a context, and mount it above the steps.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation