perf(react-form): `form.Subscribe` causes unnecessary re-renders when selector returns objects or arrays with same content
Nessuno ha ancora preso questa issue.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 76/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- react, typescript
- Ambito
- frontend
Direzione di ricerca
Leggi LocalSubscribe in packages/react-form/src/useForm.tsx e ispeziona la chiamata a useStore e la relativa API della funzione di uguaglianza in @tanstack/react-store. Aggiorna la gestione dei selettori come descritto, incluso il selettore predefinito, quindi esegui i test esistenti e conferma che le selezioni di oggetti e array non vengano renderizzate nuovamente quando cambiano campi del modulo non correlati.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Describe the bug
form.Subscribe triggers unnecessary re-renders when the selector returns an object or array, even when the underlying values have not changed. This is because LocalSubscribe in packages/react-form/src/useForm.tsx calls useStore(form.store, selector) without an equality function, so it falls back to Object.is reference equality. Since selectors that return objects/arrays create a new reference on every store update, the component re-renders every time any field in the form changes — not just the fields the selector cares about.
Screen recording
Your minimal, reproducible example
https://codesandbox.io/p/github/kevalmiistry/form-test/main?import=true
Steps to reproduce
- Open React DevTools and enable "Highlight updates when components render"
- Set Account Type to "Business"
- Set Country to "US"
- The Tax ID field appears (rendered inside the form.Subscribe block)
- Now type in any other input (e.g. the Name field)
- Observe that the form.Subscribe block (and the Tax ID field inside it) flashes/re-renders on every keystroke, even though accountType and country have not changed
Expected behavior
form.Subscribe should only re-render when the content of the selected value actually changes, not when the reference changes. A shallow equality check would solve this for the common patterns above (objects and arrays with primitive values).
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
- OS: macOS Sequoia (Darwin 25.3.0)
- Browser: Chrome (latest)
@tanstack/react-form— react adapter- Tested on latest
mainbranch (commite21cc011)
TanStack Form adapter
react-form
TanStack Form version
1.28.5
TypeScript version
No response
Additional context
Root cause
In packages/react-form/src/useForm.tsx, the LocalSubscribe component:
function LocalSubscribe({ form, selector = (state) => state, children }) {
const data = useStore(form.store, selector) // ← no equality function
return <>{functionalUpdate(children, data)}</>
}
useStore from @tanstack/react-store accepts an optional third argument — an equality function. Without it, Object.is is used, which fails for objects and arrays.
Proposed fix
- Import
shallowfrom@tanstack/react-store(already a dependency, zero cost) - Pass
shallowas the third argument touseStore - Extract the default selector to a module-level constant to fix the
@eslint-react/no-unstable-default-propslint warning
import { shallow, useStore } from '@tanstack/react-store'
const defaultSelector = (state: AnyFormState) => state
function LocalSubscribe({
form,
selector = defaultSelector,
children,
}: PropsWithChildren<{
form: AnyFormApi
selector?: (state: AnyFormState) => AnyFormState
}>) {
const data = useStore(form.store, selector, shallow)
return <>{functionalUpdate(children, data)}</>
}
This is a non-breaking change. shallow correctly handles primitives (falls back to Object.is), plain objects, arrays, Maps, Sets, and Dates. All existing tests pass.
I have already implemented this in my local setup and can confirm it is working as expected and all tests are passing post changes. I can open a PR for this if the approach looks good. In that case please assign the issue to me.
- Lingua principale
- TypeScript
- Stelle
- 6.7k
- Fork
- 682
- Merge medio
- 5g 18h
- PR unite (30g)
- 7
Guida per i contributori
Apri la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di TanStack/form
-
Difficoltà 2/5 1-2 giorni Idoneità per principianti 72/100
-
area: runtime scope: devtools type: bug v2
Difficoltà 2/5 1-3 ore Idoneità per principianti 65/100
-
area: runtime scope: core type: bug v1
Difficoltà 2/5 1-3 ore Idoneità per principianti 82/100
-
FormApi: onSubmit/onServer error cleared on any non-matching validation cause, not just 'change' Apertav1 v2: needs investigation
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
-
v1 v2: needs investigation
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
Tutte le issue di TanStack/form
Issue simili
-
Claiming namespace Londopy Aperta
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 72/100
EclipseFdn/open-vsx.org#13385 · 1 commento ·
-
S: triage
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 85/100
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
-
fix(errors): EHOSTUNREACH from a happy-eyeballs connect is reported as a resolver error (STAMP-80) Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 90/100
snapshot-labs/stamp#666 ·
-
vangogh
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
knaw-huc/textannoviz#691 ·