Skip to content

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, Preact, and Angular — allows disabling or customizing structural sharing for combined query results (defaults to true).
    • Enabled structuralSharing support in core query logic to honor the new option.
  • Documentation

    • Updated useQueries reference to document structuralSharing and its effect on 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: eabd1fc

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

This PR includes changesets to release 20 packages
Name Type
@tanstack/angular-query-experimental Minor
@tanstack/svelte-query Minor
@tanstack/react-query Minor
@tanstack/preact-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

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new public option structuralSharing?: boolean | ((oldData, newData) => unknown) across query-core and framework adapters to allow disabling or customizing structural sharing for combined useQueries results; threads the flag through optimistic-result computations, observers, docs, tests, and a changeset.

Changes

Cohort / File(s) Summary
Release Configuration
/.changeset/silver-coins-mix.md
Changeset updated to include minor bumps for multiple packages and the structuralSharing feature flag.
Documentation
docs/framework/react/reference/useQueries.md
Documented new `structuralSharing?: boolean
Core Query Logic
packages/query-core/src/queriesObserver.ts
Added structuralSharing to QueriesObserverOptions, extended getOptimisticResult signature, and applied custom/disabled structural sharing in combine/result computation and notify paths.
Core Tests
packages/query-core/src/__tests__/queriesObserver.test.tsx
Updated getOptimisticResult call sites to include the new third argument (structuralSharing/undefined) across tests.
React Implementation
packages/react-query/src/useQueries.ts
Exposed structuralSharing on useQueries options and forwarded it to observer.getOptimisticResult.
Vue Implementation
packages/vue-query/src/useQueries.ts
Added structuralSharing to UseQueriesOptions and forwarded it into observer optimistic-result and refetch paths.
Solid Implementation
packages/solid-query/src/useQueries.ts
Added structuralSharing to queries options and threaded it into observer optimistic-result and update flows.
Svelte Implementation
packages/svelte-query/src/createQueries.svelte.ts
Added structuralSharing to public options, unified derived options handling, and passed it into QueriesObserver and optimistic result creation.
Angular Implementation
packages/angular-query-experimental/src/inject-queries.ts
Added structuralSharing to InjectQueriesOptions and forwarded it to getOptimisticResult during optimistic computation.
Preact Implementation
packages/preact-query/src/useQueries.ts
Added structuralSharing option and forwarded it to observer.getOptimisticResult.

Sequence Diagram(s)

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

  Hook->>Observer: construct(queries, combine?, structuralSharing?)
  Hook->>Observer: 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->>Observer: apply structuralSharing?
    Observer-->>Result: combined (possibly shared) result
  else no combine
    Observer-->>Result: array of per-query results
  end
  Observer-->>Hook: optimistic result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • TkDodo

Poem

🐰
I nibble flags and hop through code so spry,
A toggle for sharing—decide how results tie.
Through hooks and core I bound and play,
Share or keep, the choice hops your way! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.29% 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 affected packages.
Description check ✅ Passed The description follows the template structure with all required sections completed: Changes section explains the feature clearly, both checklist items are marked as completed, and release impact indicates a changeset was generated.

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

✨ Finishing touches
🧪 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`.
* Only applies when `combine` is provided.
* Defaults to `true`.
*/
structuralSharing?: boolean
Copy link
Collaborator

Choose a reason for hiding this comment

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

as with the standard option on useQuery, this should also accept a function.

Copy link
Author

Choose a reason for hiding this comment

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

Done. The signature is the same as the regular useQuery-hook and I updated all the adapters.

---
'@tanstack/angular-query-experimental': minor
'@tanstack/svelte-query': minor
'@tanstack/react-query': minor
Copy link
Collaborator

Choose a reason for hiding this comment

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

please also do the new preact adapter

Copy link
Author

Choose a reason for hiding this comment

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

Done ✅

Comment on lines 255 to 259
const combined = combine(input)

this.#combinedResult = structuralSharing
? replaceEqualDeep(this.#combinedResult, combined)
: combined
Copy link
Collaborator

Choose a reason for hiding this comment

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

please add some tests where false is passed

Copy link
Author

Choose a reason for hiding this comment

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

Added tests for both false, true and passing a function.

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: 1

🤖 Fix all issues with AI agents
In `@docs/framework/react/reference/useQueries.md`:
- Around line 27-31: Update the `structuralSharing` option docs to state the
prerequisite that it "Only applies when `combine` is provided"; specifically, in
the `structuralSharing?: boolean | ((oldData: unknown | undefined, newData:
unknown) => unknown)` description add a concise note that this setting has
effect only if `combine` is supplied, referencing the `combine` option so
readers understand the dependency between `structuralSharing` and `combine`.
🧹 Nitpick comments (1)
packages/svelte-query/src/createQueries.svelte.ts (1)

215-216: Including structuralSharing in derivedCreateQueriesOptions may trigger unnecessary observer recreation.

Since observer is $derived from derivedCreateQueriesOptions (line 229-235), changing only structuralSharing will recreate the entire QueriesObserver. The constructor doesn't use structuralSharing — it's only consumed later by getOptimisticResult and #combineResult. This is the same pre-existing trade-off as combine changes causing recreation, so it's not a regression, but worth noting for potential future optimization.

Also applies to: 229-235

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.

2 participants