Skip to content

feat(query-core): add structuralSharing option to useQueries#10101

Open
dagstuan wants to merge 1 commit intoTanStack:mainfrom
dagstuan:main
Open

feat(query-core): add structuralSharing option to useQueries#10101
dagstuan wants to merge 1 commit intoTanStack:mainfrom
dagstuan:main

Conversation

@dagstuan
Copy link

@dagstuan dagstuan commented Feb 6, 2026

🎯 Changes

Add a structuralSharing option to useQueries/createQueries/injectQueries that allows disabling structural sharing for the combined result. When set to false, the combined result will not use replaceEqualDeep for referential stability. Defaults to true.

Full disclosure: Docs were generated by Claude, all other implementation was done without AI.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test:pr.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • New Features

    • Added an optional structuralSharing option to useQueries across React, Vue, Svelte, Solid, and Angular — allows disabling structural sharing for combined query results (defaults to true).
  • Documentation

    • Updated useQueries reference to document the structuralSharing option and how it affects combined results.
  • Chores

    • Bumped minor versions for multiple query packages and added a changeset entry.

@changeset-bot
Copy link

changeset-bot bot commented Feb 6, 2026

🦋 Changeset detected

Latest commit: 1956f42

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
Name Type
@tanstack/angular-query-experimental Minor
@tanstack/svelte-query Minor
@tanstack/react-query Minor
@tanstack/solid-query Minor
@tanstack/query-core Minor
@tanstack/vue-query Minor
@tanstack/angular-query-persist-client Major
@tanstack/svelte-query-devtools Major
@tanstack/svelte-query-persist-client Major
@tanstack/react-query-devtools Major
@tanstack/react-query-next-experimental Major
@tanstack/react-query-persist-client Major
@tanstack/solid-query-devtools Major
@tanstack/solid-query-persist-client Major
@tanstack/query-async-storage-persister Patch
@tanstack/query-broadcast-client-experimental Patch
@tanstack/query-persist-client-core Patch
@tanstack/query-sync-storage-persister Patch
@tanstack/vue-query-devtools Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

Adds a new boolean option structuralSharing (default true) across TanStack Query packages to allow disabling structural sharing for combined useQueries results; threads the flag through Query core (QueriesObserver), framework hooks (React/Vue/Solid/Svelte/Angular), tests, docs, and a changeset.

Changes

Cohort / File(s) Summary
Release Configuration
/.changeset/silver-coins-mix.md
New changeset documenting minor package bumps and the structuralSharing feature.
Documentation
docs/framework/react/reference/useQueries.md
Documented structuralSharing?: boolean for useQueries and clarified default and Combine interaction.
Core Query Logic
packages/query-core/src/queriesObserver.ts
Added structuralSharing?: boolean to QueriesObserverOptions, extended getOptimisticResult(..., structuralSharing?), and applied the flag in combine/result computation and notification paths.
Core Tests
packages/query-core/src/__tests__/queriesObserver.test.tsx
Updated observer.getOptimisticResult call sites to include an extra third argument (structuralSharing/undefined) to match the new signature.
React Implementation
packages/react-query/src/useQueries.ts
Exposed structuralSharing?: boolean on useQueries options and forwarded it to observer.getOptimisticResult.
Vue Implementation
packages/vue-query/src/useQueries.ts
Added structuralSharing?: boolean to UseQueriesOptions and forwarded it into observer optimistic-result and refetch paths.
Solid Implementation
packages/solid-query/src/useQueries.ts
Added structuralSharing?: boolean to queries options and threaded it into observer optimistic-result and update flows.
Svelte Implementation
packages/svelte-query/src/createQueries.svelte.ts
Extended public options to include structuralSharing, unified derived options handling, and passed them into QueriesObserver and createResult flows.
Angular Implementation
packages/angular-query-experimental/src/inject-queries.ts
Added structuralSharing?: boolean to InjectQueriesOptions and forwarded it to getOptimisticResult during optimistic computation.

Sequence Diagram(s)

sequenceDiagram
  participant Hook as Framework Hook (useQueries)
  participant Observer as QueriesObserver (query-core)
  participant Combine as CombineFn (user)
  participant Result as Combined Result

  Hook->>Observer: construct(queries, combine?, structuralSharing?)
  Hook->>Observer: request getOptimisticResult(queries, combine, structuralSharing)
  Observer->>Observer: compute per-query optimistic results
  alt combine provided
    Observer->>Combine: call combine(per-query results)
    Combine-->>Observer: combined value
    Observer->>Result: apply structuralSharing? → replaceEqualDeep or return new result
  else no combine
    Observer->>Result: return array of per-query results
  end
  Observer-->>Hook: optimistic result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #9954: Modifies QueriesObserver's optimistic/combine workflow — overlaps with the new getOptimisticResult signature and flag plumbing.
  • PR #9914: Touches packages/vue-query/src/useQueries.ts — relates to changes in Vue useQueries options/handling.
  • PR #8690: Alters packages/angular-query-experimental/src/inject-queries.ts — overlaps with InjectQueriesOptions shape and option forwarding.

Suggested reviewers

  • TkDodo
  • arnoud-dv

Poem

🐰
I nibble flags and hop through code so fine,
A little toggle makes combined results align.
Through hooks and core I bounce with glee,
Share or not — the choice is free! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: adding a structuralSharing option to useQueries in query-core, which is the core feature across all the modified files.
Description check ✅ Passed The description follows the required template with all key sections completed: changes are clearly explained, checklist items are marked as completed, and release impact is documented with a changeset.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/solid-query/src/useQueries.ts (1)

312-332: ⚠️ Potential issue | 🔴 Critical

Bug: structuralSharing is not passed to observer.setQueries() in the Solid adapter.

Both setQueries call sites (lines 313–320 and 324–331) manually construct the options object with only combine, omitting structuralSharing. This causes the observer's internal #options.structuralSharing to be undefined after mount/update, resulting in subscription-driven notifications ignoring the user's structuralSharing: false setting.

All other framework adapters (React, Vue, Svelte, Angular) pass the full options object including structuralSharing to setQueries.

Proposed fix
   onMount(() => {
     observer.setQueries(
       defaultedQueries(),
-      queriesOptions().combine
-        ? ({
-            combine: queriesOptions().combine,
-          } as QueriesObserverOptions<TCombinedResult>)
-        : undefined,
+      queriesOptions() as QueriesObserverOptions<TCombinedResult>,
     )
   })
 
   createComputed(() => {
     observer.setQueries(
       defaultedQueries(),
-      queriesOptions().combine
-        ? ({
-            combine: queriesOptions().combine,
-          } as QueriesObserverOptions<TCombinedResult>)
-        : undefined,
+      queriesOptions() as QueriesObserverOptions<TCombinedResult>,
     )
   })

The extra queries property in queriesOptions() will be passed to setQueries but safely ignored at runtime since QueriesObserverOptions only has combine and structuralSharing properties.

🤖 Fix all issues with AI agents
In @.changeset/silver-coins-mix.md:
- Line 10: The changeset message contains a typo "strucuralSharing"; update the
changes text to read "structuralSharing" so the feature line reads:
feat(query-core): Allow disabling structuralSharing for useQueries, ensuring the
corrected spelling replaces the incorrect "strucuralSharing" token in the
changeset entry.

In `@packages/query-core/src/queriesObserver.ts`:
- Around line 33-37: The JSDoc claim that structuralSharing disables structural
sharing is inaccurate because replaceEqualDeep is only called inside the combine
branch (see combine usage around replaceEqualDeep and return of input), so
structuralSharing: false is a no-op when combine is undefined; either update the
JSDoc (and corresponding adapter docs) to state structuralSharing only applies
when combine is provided, or change the non-combine path to respect the flag by
applying the same replaceEqualDeep logic to the returned input (use the existing
replaceEqualDeep helper and the structuralSharing boolean where the function
currently returns input directly) so structuralSharing:false actually prevents
structural sharing in both code paths (adjust code around the combine check and
the final return to call replaceEqualDeep when appropriate).
🧹 Nitpick comments (1)
packages/query-core/src/__tests__/queriesObserver.test.tsx (1)

296-305: Missing test coverage for structuralSharing: false.

All existing tests pass undefined (defaulting to true). There are no tests verifying that structuralSharing: false actually skips replaceEqualDeep and produces a new reference for the combined result. Consider adding a test that asserts referential inequality when structuralSharing is false with a combine function, and referential equality when it's true.

@dagstuan dagstuan force-pushed the main branch 4 times, most recently from 368a0b7 to 21e9f59 Compare February 6, 2026 20:59
Add a `structuralSharing` option to useQueries/createQueries/injectQueries
that allows disabling structural sharing for the combined result. When set
to `false`, the combined result will not use `replaceEqualDeep` for
referential stability. Defaults to `true`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant