Skip to content

fix(svelte-store): use .raw in useSelector to avoid proxy equality mismatch - #381

Closed
grzdev wants to merge 1 commit into
TanStack:mainfrom
grzdev:fix/svelte-store-state-raw-selector
Closed

grzdev wants to merge 1 commit into
TanStack:mainfrom
grzdev:fix/svelte-store-state-raw-selector

Conversation

@grzdev

@grzdev grzdev commented Oct 8, 2026 •

Copy link
Copy Markdown

Summary of Changes

In Svelte 5, using $state(selector(source.get())) wraps any selected objects or arrays in deeply reactive proxies. This causes several issues when using useSelector:

  1. Comparing compare(slice, data) compares the reactive proxy in slice with the raw object from data. Under default reference comparison (===), a Proxy never strictly equals the raw target object, causing false positives and triggering unnecessary updates on unaffected objects.
  2. Svelte 5 triggers state_proxy_equality_mismatch warnings / errors in development when checking proxy vs raw object equality.
  3. Callers reading storeVal.current receive a proxy rather than the raw object reference, defeating reference equality checks across component boundaries.

This change switches useSelector's internal state holder to let slice = $state.raw(selector(source.get())). Because the selector state holder is updated via reassignment (slice = data), $state.raw retains full reactive signaling when values change while preserving reference identity and avoiding unwanted proxy wrapping.

Validation

  • Added a unit test in packages/svelte-store ensuring object reference identity is preserved and unchanged object selections do not trigger spurious re-renders.
  • Verified all vitest tests and svelte-check type checks pass.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed object selection in @tanstack/svelte-store to preserve original object references and avoid unnecessary re-renders when unrelated store values change.
    • Updates to nested selected values continue to trigger re-renders.

@coderabbitai

coderabbitai Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: c6dafc75-d41d-46a3-942e-8bb510176492
📥 Commits

Reviewing files that changed from the base of the PR and between c1a40d4 and 48ca363.

📒 Files selected for processing (4)
  • .changeset/svelte-store-raw-state.md
  • packages/svelte-store/src/useSelector.svelte.ts
  • packages/svelte-store/tests/ObjectRender.test.svelte
  • packages/svelte-store/tests/index.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 2 remain after this review.


📝 Walkthrough

Walkthrough

useSelector now initializes its selected value with $state.raw. Tests check that the selected object retains its original reference, unrelated updates do not trigger a re-render, and nested updates do.

Changes

Selector state

Layer / File(s) Summary
Initialize selection with raw state
packages/svelte-store/src/useSelector.svelte.ts, .changeset/svelte-store-raw-state.md
useSelector initializes slice with $state.raw instead of $state. A patch changeset records the change.
Verify object selection behavior
packages/svelte-store/tests/ObjectRender.test.svelte, packages/svelte-store/tests/index.test.ts
A new test checks selected-object identity and render behavior after unrelated and nested store updates.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Possibly related PRs

  • TanStack/store#364: Both changes initialize useSelector state with $state.raw and cover raw object identity.

Merge Risk: ⚪ Minimal · up to 48ca3

The selector change has no identified issue requiring a fix before merge.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the motivation, implementation, and validation. It does not include the required ## 🎯 Changes, ## ✅ Checklist, or ## 🚀 Release Impact sections, and it does not record th… Add the required template sections. Mark the contributing-guide and pnpm test:pr checklist items. Confirm the release impact by selecting the published-code option and noting the generated changeset, or select the docs/CI/dev-only option …
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: using raw state in useSelector to prevent proxy equality mismatches.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. (2 skipped: 2 …
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description explains the motivation, implementation, and validation. It does not include the required ## 🎯 Changes, ## ✅ Checklist, or ## 🚀 Release Impact sections, and it does not record the checklist status or changeset impact.

Resolution

Add the required template sections. Mark the contributing-guide and pnpm test:pr checklist items. Confirm the release impact by selecting the published-code option and noting the generated changeset, or select the docs/CI/dev-only option if applicable.

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/svelte-store/src/useSelector.svelte.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

packages/svelte-store/tests/ObjectRender.test.svelte

ESLint skipped: the matched ESLint configuration already failed (missing-dependency).

packages/svelte-store/tests/index.test.ts

ESLint skipped: the matched ESLint configuration already failed (missing-dependency).


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.

@crutchcorn

Copy link
Copy Markdown
Member

Sorry, dupe of #364 which just got merged

@crutchcorn crutchcorn closed this Oct 9, 2026
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.

2 participants