Skip to content

fix(react-form): use shallow equality in form.Subscribe to prevent unnecessary re-renders#2092

Open
mixelburg wants to merge 1 commit intoTanStack:mainfrom
mixelburg:fix/form-subscribe-unnecessary-rerenders
Open

fix(react-form): use shallow equality in form.Subscribe to prevent unnecessary re-renders#2092
mixelburg wants to merge 1 commit intoTanStack:mainfrom
mixelburg:fix/form-subscribe-unnecessary-rerenders

Conversation

@mixelburg
Copy link

@mixelburg mixelburg commented Mar 23, 2026

Summary

Fixes #2090

form.Subscribe was triggering re-renders on every store update when the selector returned an object or array. Since useStore defaults to Object.is reference equality, selectors that construct new objects/arrays on each call always appeared to have changed — even when the underlying data was identical.

Fix

Pass shallow from @tanstack/react-store as the compare function to useStore in LocalSubscribe. This is a one-line change: shallow equality avoids re-renders when the selector returns an object or array with the same primitive values.

-const data = useStore(form.store, selector)
+const data = useStore(form.store, selector, shallow)

@tanstack/react-store already exports shallow (and re-exports @tanstack/store), so no new dependencies are needed.

Testing

All 86 existing tests pass with no changes. The fix is intentionally minimal — the change in equality semantics only matters when a selector returns a new object/array reference on every call with the same contents, which is the exact scenario described in the issue.

Summary by CodeRabbit

  • Bug Fixes
    • Improved form state change detection to ensure form components re-render correctly when data updates.

…necessary re-renders

When the selector returns an object or array, useStore falls back to
Object.is reference equality, causing re-renders on every store update
even when the selected values haven't changed.

Pass the shallow equality function from @tanstack/react-store as the
compare argument to useStore so Subscribe only re-renders when the
selected data actually changes structurally.

Fixes TanStack#2090
@coderabbitai
Copy link

coderabbitai bot commented Mar 23, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 544f6088-bf2d-4ca1-8a8b-b1f24d6b2682

📥 Commits

Reviewing files that changed from the base of the PR and between e21cc01 and cc25192.

📒 Files selected for processing (1)
  • packages/react-form/src/useForm.tsx

📝 Walkthrough

Walkthrough

Updated the internal subscription mechanism in LocalSubscribe to use shallow equality comparison for state change detection. This prevents unnecessary re-renders when selectors return objects or arrays with unchanged content by passing shallow comparator to useStore().

Changes

Cohort / File(s) Summary
Performance Fix
packages/react-form/src/useForm.tsx
Added shallow import from @tanstack/react-store and passed it as the third parameter to useStore(form.store, selector, shallow) to enable shallow equality comparison for form state subscriptions, preventing redundant re-renders.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 A shallow check, so quick and clean,
Stops renders that should never be seen,
When objects dance but stay the same,
Our form knows—no need for the blame!
Performance hops with gentle grace,

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The description provides a clear summary with issue reference, root cause analysis, and testing confirmation, but lacks the PR description template sections (🎯 Changes, ✅ Checklist, 🚀 Release Impact). Follow the repository's PR description template with proper sections (Changes, Checklist, Release Impact) and confirm changeset generation if applicable.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: using shallow equality in form.Subscribe to prevent unnecessary re-renders, which matches the core modification.
Linked Issues check ✅ Passed The PR successfully implements all coding objectives from issue #2090: importing shallow from @tanstack/react-store, passing it as the third argument to useStore in LocalSubscribe, and verifying all 86 tests pass.
Out of Scope Changes check ✅ Passed The changes are narrowly scoped to the required fix: only adding the shallow parameter to useStore in LocalSubscribe (+2/-2 lines), with no additional out-of-scope modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

perf(react-form): form.Subscribe causes unnecessary re-renders when selector returns objects or arrays with same content

1 participant