Skip to content

Conversation

joseph0926
Copy link
Contributor

@joseph0926 joseph0926 commented Sep 5, 2025

Fixes #8781
Closes #9207 : He had taken ownership of the fix, and his proposed direction was similar to mine. However, since there has been no response for several months and no tests seem to be included, I am opening an additional PR to help resolve the issue. If there is a rule that prevents someone else from submitting a PR once an issue has already been assigned, I will be happy to close this one.

Description

combine function with stable reference not updating correctly when queries change
On the other hand, combine implemented as an inline function works correctly because the reference changes each time.

combine !== this.#lastCombine

Problem

When using useQueries with a stable reference for the combine function, the combined result was not updated immediately when the queries array changed. This resulted in stale data being returned for one render cycle.

Root Cause

The caching logic in #combineResult was comparing this.#result to determine cache invalidation, but the actual data being processed was the input parameter. When getOptimisticResult generated a new result array, this.#result hadn't been updated yet (happens later in useEffect), causing incorrect cache hits.

Solution

Added input.length !== this.#lastInput?.length check to the cache invalidation logic. This ensures the cache is properly invalidated when the number of queries changes, which is the most common scenario.

Why length comparison is sufficient

While comparing only the length might seem incomplete, it works because,

  1. Most real-world cases involve changing the number of queries
  2. For same-length changes, setQueries is called via useEffect which updates this.#result for the next render
  3. This approach maintains the original performance optimization intent while fixing the bug

Testing

  • stable reference combine should update immediately when queries change
  • inline combine should update immediately when queries change
  • should handle dynamic query array changes correctly
  • should handle same length but different queries
  • should handle query order changes with same length
  • should handle combine function that transforms data
  • should not break when switching between stable and inline combine

All existing tests continue to pass, ensuring backward compatibility.


No breaking changes – this is a targeted optimization

Alternative approaches considered

  • Full input reference comparison: Would cause excessive cache misses
    • input.length !== this.#lastInput: This has been confirmed to significantly impact existing caching to the point of breaking existing caching tests.
  • Content-based comparison: Performance overhead
    • While it might be possible to achieve this by adding an additional flag to #combineResult and redesigning it, we determined that the overall impact would be too significant.
  • Separate optimistic cache: Over-engineering for the use case
    • Perhaps something like this...? #combineCache = new WeakMap<Array<QueryObserverResult>, TCombinedResult>()
      It might be possible, but I judged it to be overhead.

Summary by CodeRabbit

  • Bug Fixes

    • useQueries combine now reliably recomputes when the number of queries changes, when query order changes, when switching between stable and inline combine implementations, and during optimistic-update scenarios so result length, counts, and data stay in sync.
  • Tests

    • Added comprehensive tests for combine memoization, dynamic query arrays, transformed combine results, stability between combine implementations, and cache invalidation when query count changes.

Copy link

coderabbitai bot commented Sep 5, 2025

Walkthrough

Adds input-length tracking to QueriesObserver.#combineResult so recomputation occurs when the input array size changes (e.g., optimistic updates). Stores the last input and updates it on recompute. Adds tests exercising useQueries combine behavior across stable/inline combines and dynamic query arrays.

Changes

Cohort / File(s) Summary
Core: QueriesObserver combine recomputation
packages/query-core/src/queriesObserver.ts
Adds private field #lastInput?: Array<QueryObserverResult>; extends recomputation condition in #combineResult to check input.length !== this.#lastInput?.length; sets this.#lastInput = input when recomputing; comment about optimistic updates.
Core tests: QueriesObserver behavior
packages/query-core/src/__tests__/queriesObserver.test.tsx
Adds unit test(s) verifying a stable combine reference triggers recompute when query count increases and that combine receives the updated input array.
React Query tests: useQueries combine behavior
packages/react-query/src/__tests__/useQueries-combine.test.tsx
New test suite covering stable vs inline combine, dynamic query arrays, transformCombine, switching combine implementations, same-length different queries, and query reordering effects.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor C as Component
  participant RQ as useQueries Hook
  participant QO as QueriesObserver
  participant QC as QueryCache

  C->>RQ: render({ queries[], combine })
  RQ->>QC: read query results
  QC-->>RQ: QueryObserverResults[] (input)
  RQ->>QO: #combineResult(input)

  rect rgba(200,230,255,0.25)
    note right of QO: New: track lastInput length
    QO->>QO: if !#lastCombine or !#lastResult
    QO->>QO: or input.length != #lastInput?.length
    QO->>QO: or input !== #lastResult
    alt recompute
      QO->>QO: #combinedResult = combine(input)
      QO->>QO: #lastInput = input
      QO->>QO: update #lastCombine / #lastResult
    else
      QO->>QO: return cached #combinedResult
    end
  end

  QO-->>RQ: combined result
  RQ-->>C: hook result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Fix combine stable reference not called with correct parameters when query count changes (#8781)
Add length check in QueriesObserver.#combineResult to decide recomputation for optimistic vs updated results (#9207)

Out-of-scope changes

Code Change Explanation
Duplicate test insertion in packages/query-core/src/__tests__/queriesObserver.test.tsx (two identical tests added) Appears to be an accidental duplicate test addition not required by the linked issues; duplicates test coverage rather than addressing combine logic.

Possibly related PRs

Suggested reviewers

  • TkDodo

Poem

I hop through arrays, count each tiny bit,
When lengths do change, I nudge the logic fit.
Stable ears now hear the growing crowd,
Combine aligns — my whiskers proud. 🥕🐇


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c515b4c and d8050a9.

📒 Files selected for processing (1)
  • packages/query-core/src/__tests__/queriesObserver.test.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/query-core/src/tests/queriesObserver.test.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

nx-cloud bot commented Sep 5, 2025

View your CI Pipeline Execution ↗ for commit 02ddb7e

Command Status Duration Result
nx affected --targets=test:sherif,test:knip,tes... ✅ Succeeded 2m 25s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 35s View ↗

☁️ Nx Cloud last updated this comment at 2025-09-08 13:22:54 UTC

Copy link

pkg-pr-new bot commented Sep 5, 2025

More templates

@tanstack/angular-query-devtools-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-devtools-experimental@9618

@tanstack/angular-query-experimental

npm i https://pkg.pr.new/@tanstack/angular-query-experimental@9618

@tanstack/eslint-plugin-query

npm i https://pkg.pr.new/@tanstack/eslint-plugin-query@9618

@tanstack/query-async-storage-persister

npm i https://pkg.pr.new/@tanstack/query-async-storage-persister@9618

@tanstack/query-broadcast-client-experimental

npm i https://pkg.pr.new/@tanstack/query-broadcast-client-experimental@9618

@tanstack/query-core

npm i https://pkg.pr.new/@tanstack/query-core@9618

@tanstack/query-devtools

npm i https://pkg.pr.new/@tanstack/query-devtools@9618

@tanstack/query-persist-client-core

npm i https://pkg.pr.new/@tanstack/query-persist-client-core@9618

@tanstack/query-sync-storage-persister

npm i https://pkg.pr.new/@tanstack/query-sync-storage-persister@9618

@tanstack/react-query

npm i https://pkg.pr.new/@tanstack/react-query@9618

@tanstack/react-query-devtools

npm i https://pkg.pr.new/@tanstack/react-query-devtools@9618

@tanstack/react-query-next-experimental

npm i https://pkg.pr.new/@tanstack/react-query-next-experimental@9618

@tanstack/react-query-persist-client

npm i https://pkg.pr.new/@tanstack/react-query-persist-client@9618

@tanstack/solid-query

npm i https://pkg.pr.new/@tanstack/solid-query@9618

@tanstack/solid-query-devtools

npm i https://pkg.pr.new/@tanstack/solid-query-devtools@9618

@tanstack/solid-query-persist-client

npm i https://pkg.pr.new/@tanstack/solid-query-persist-client@9618

@tanstack/svelte-query

npm i https://pkg.pr.new/@tanstack/svelte-query@9618

@tanstack/svelte-query-devtools

npm i https://pkg.pr.new/@tanstack/svelte-query-devtools@9618

@tanstack/svelte-query-persist-client

npm i https://pkg.pr.new/@tanstack/svelte-query-persist-client@9618

@tanstack/vue-query

npm i https://pkg.pr.new/@tanstack/vue-query@9618

@tanstack/vue-query-devtools

npm i https://pkg.pr.new/@tanstack/vue-query-devtools@9618

commit: 02ddb7e

Copy link

@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: 0

🧹 Nitpick comments (3)
packages/query-core/src/queriesObserver.ts (1)

46-47: Add a brief doc comment for #lastInput

A one-liner clarifying that #lastInput tracks the last optimistic input used for combine to detect shape (length) changes would aid future maintainers.

Apply near-field doc:

-  #lastInput?: Array<QueryObserverResult>
+  // Last optimistic input passed to #combineResult; used to detect shape (length) changes before #result updates.
+  #lastInput?: Array<QueryObserverResult>
packages/react-query/src/__tests__/useQueries-combine.test.tsx (2)

231-272: Same-length key changes assert eventual data, not immediate combine result

These assertions wait for data and don’t validate whether the combined result updates in the same render when keys change but length stays constant. If the intended behavior allows one interim render with the previous combined cache for same-length changes, consider adding a short inline comment to the test noting this expectation to prevent future “tightening” attempts.


1-22: Reduce duplication: factor a test helper to create client/wrapper

Each test repeats new QueryClient and wrapper. Consider a small factory to DRY this up and ensure consistent defaults (and optional teardown).

Example helper:

+function createTestWrapper() {
+  const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } })
+  const wrapper = ({ children }: { children: React.ReactNode }) => (
+    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
+  )
+  return { queryClient, wrapper }
+}

Then in tests:

-const queryClient = new QueryClient({ ... })
-const wrapper = ({ children }: { children: React.ReactNode }) => ( ... )
+const { queryClient, wrapper } = createTestWrapper()

Optionally call queryClient.clear() at test end to avoid lingering GC timers.

Also applies to: 54-65, 96-107, 151-153, 197-199, 241-242, 284-285

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2283633 and 6387623.

📒 Files selected for processing (2)
  • packages/query-core/src/queriesObserver.ts (2 hunks)
  • packages/react-query/src/__tests__/useQueries-combine.test.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
packages/react-query/src/__tests__/useQueries-combine.test.tsx (2)
packages/query-core/src/queriesObserver.ts (2)
  • queries (238-264)
  • result (195-210)
packages/react-query/src/__tests__/useQueries.test.tsx (1)
  • key1 (1091-1190)
packages/query-core/src/queriesObserver.ts (1)
packages/query-core/src/types.ts (1)
  • QueryObserverResult (899-904)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Test
  • GitHub Check: Preview
🔇 Additional comments (7)
packages/query-core/src/queriesObserver.ts (3)

46-46: Track last input to break stale combine cache — good addition

Adding #lastInput enables detecting optimistic input shape changes independent of #result updates. This unblocks the stale-one-render bug for length changes.


220-227: Invalidate combine cache on input length change — fix is correct and minimal

The extra input.length !== this.#lastInput?.length guard precisely targets the stale case introduced by optimistic inputs while preserving perf. Updating #lastInput only on recompute keeps cache hits stable.


220-221: Confirm intended behavior for same-length input changes

This fix handles length deltas immediately. For same-length but reordered/replaced queries, we still rely on setQueries driving #result !== #lastResult to trigger recompute, which may allow one interim render using the prior combined cache. Please confirm this is acceptable per #9207’s trade-off, or call out the behavior in docs.

packages/react-query/src/__tests__/useQueries-combine.test.tsx (4)

10-52: Stable combine: immediate length updates — solid regression test

Covers the exact bug surface (0→1→2) and asserts sync length changes without waiting for data. Nice.


94-140: Dynamic add/remove sequences — good breadth

Validates increases and decreases; keeps assertions focused on length, which is what the fix targets.


142-186: Transforming combine results — verifies non-array shapes

Ensures memoization works when combine returns objects with derived fields. Looks good.


188-229: Switching stable/inline combine — interoperability check passes

Covers toggling function identity without regressions. Good safety net.

Copy link

codecov bot commented Sep 5, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.90%. Comparing base (ccedf33) to head (02ddb7e).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##             main    #9618       +/-   ##
===========================================
+ Coverage   45.50%   59.90%   +14.40%     
===========================================
  Files         209      138       -71     
  Lines        8377     5617     -2760     
  Branches     1897     1512      -385     
===========================================
- Hits         3812     3365      -447     
+ Misses       4118     1949     -2169     
+ Partials      447      303      -144     
Components Coverage Δ
@tanstack/angular-query-devtools-experimental ∅ <ø> (∅)
@tanstack/angular-query-experimental 87.00% <ø> (ø)
@tanstack/eslint-plugin-query ∅ <ø> (∅)
@tanstack/query-async-storage-persister 43.85% <ø> (ø)
@tanstack/query-broadcast-client-experimental 24.39% <ø> (ø)
@tanstack/query-codemods ∅ <ø> (∅)
@tanstack/query-core 98.32% <100.00%> (+0.84%) ⬆️
@tanstack/query-devtools 3.48% <ø> (ø)
@tanstack/query-persist-client-core 79.60% <ø> (ø)
@tanstack/query-sync-storage-persister 84.61% <ø> (ø)
@tanstack/query-test-utils ∅ <ø> (∅)
@tanstack/react-query 96.00% <ø> (ø)
@tanstack/react-query-devtools 10.00% <ø> (ø)
@tanstack/react-query-next-experimental ∅ <ø> (∅)
@tanstack/react-query-persist-client 100.00% <ø> (ø)
@tanstack/solid-query 78.13% <ø> (ø)
@tanstack/solid-query-devtools ∅ <ø> (∅)
@tanstack/solid-query-persist-client 100.00% <ø> (ø)
@tanstack/svelte-query 87.58% <ø> (ø)
@tanstack/svelte-query-devtools ∅ <ø> (∅)
@tanstack/svelte-query-persist-client 100.00% <ø> (ø)
@tanstack/vue-query 71.10% <ø> (ø)
@tanstack/vue-query-devtools ∅ <ø> (∅)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link

@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: 0

🧹 Nitpick comments (2)
packages/query-core/src/__tests__/queriesObserver.test.tsx (2)

419-432: Strengthen assertions to prove we combined the new, longer input

Right now we only assert that the call count increased. Also assert that at least one combine call received an input of length 2, and that we observed a new emission post-update.

Apply:

@@
-    const initialCallCount = combine.mock.calls.length
+    const initialCallCount = combine.mock.calls.length
+    const baselineResults = results.length
@@
-    expect(combine.mock.calls.length).toBeGreaterThan(initialCallCount)
-    expect(results[results.length - 1]).toHaveLength(2)
+    expect(combine.mock.calls.length).toBeGreaterThan(initialCallCount)
+    expect(
+      combine.mock.calls.some((call) => Array.isArray(call[0]) && call[0].length === 2),
+    ).toBe(true)
+    expect(results.length).toBeGreaterThan(baselineResults)
+    expect(results[results.length - 1]).toHaveLength(2)

412-416: Ensure unsubscribe always runs

Wrap with try/finally so a failed assertion doesn’t leak the subscription in CI.

Apply:

-    const unsubscribe = observer.subscribe((result) => {
-      results.push(result)
-    })
+    const unsubscribe = observer.subscribe((result) => {
+      results.push(result)
+    })
+    try {
@@
-    expect(results[results.length - 1]).toHaveLength(2)
-
-    unsubscribe()
+    expect(results[results.length - 1]).toHaveLength(2)
+    } finally {
+      unsubscribe()
+    }

Also applies to: 434-435

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between abc9c0d and c515b4c.

📒 Files selected for processing (1)
  • packages/query-core/src/__tests__/queriesObserver.test.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/query-core/src/__tests__/queriesObserver.test.tsx (1)
packages/query-core/src/queriesObserver.ts (2)
  • observer (267-273)
  • result (196-211)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Preview
  • GitHub Check: Test
🔇 Additional comments (1)
packages/query-core/src/__tests__/queriesObserver.test.tsx (1)

398-411: Good targeted regression test for stable combine invalidation

Covers the 1→2 query-count change with a stable combine reference and ensures cache invalidation kicks in. Nice alignment with the bug’s root cause.

Comment on lines +221 to +222
// Compare input.length to handle optimistic updates where input differs from this.#result
input.length !== this.#lastInput?.length ||
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don’t think a length check is what we want here. What about situations where the length is the same, but data inside it changed?

I’m honestly not sure why input would change, but the check for this.#result !== this.#lastResult would still see things as being equal. That’s what we need to find out imo

Copy link
Contributor Author

@joseph0926 joseph0926 Sep 5, 2025

Choose a reason for hiding this comment

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

I’m honestly not sure why input would change, but the check for this.#result !== this.#lastResult would still see things as being equal. That’s what we need to find out imo

When getOptimisticResult is called, a new input is created—but this happens at render time.

// note: this must be called before useSyncExternalStore
const [optimisticResult, getCombinedResult, trackResult] =
observer.getOptimisticResult(
defaultedQueries,
(options as QueriesObserverOptions<TCombinedResult>).combine,
)

On the other hand, observer.setQueries is executed inside useEffect, which means it runs at commit time.

React.useEffect(() => {
observer.setQueries(
defaultedQueries,
options as QueriesObserverOptions<TCombinedResult>,
)
}, [defaultedQueries, options, observer])

In other words, at the moment getOptimisticResult is called, the input already reflects the new value, but this.#result still holds the previous value.

Because of this timing difference, the following sequence occurs

First render

  1. this.#result = [], this.#lastResult = undefinedgetOptimisticResult is called → input = [] is created
  2. #combineResult is called → since this.#lastResult = this.#result, the result becomes this.#result = [], this.#lastResult = []
  3. useEffect() { setQueries ... } runs

Second render
4. getOptimisticResult is called → input = [query1], while this.#result = [], this.#lastResult = []
5. #combineResult is called → still this.#result === this.#lastResult ([] === [])
6. useEffect() { setQueries ... } runs → this.#result = [query1]


For this reason, a discrepancy arises between the result and the input
From a semantic perspective, it would indeed be more accurate to add a comparison such as,
input !== this.#result && input !== this.#lastInput

However, while this approach handles optimistic updates well, I believe it could also cause excessive cache misses in regular updates. That is why I chose the alternative solution of comparing lengths instead

Regarding your concern about edge cases—such as when the arrays have the same length but different order—I confirmed through the additional tests I wrote ("should handle same length but different queries" and "should handle query order changes with same length") that no issues arise there. Based on that, I decided to adopt this solution as the final choice.

That said, as you pointed out, this method is ultimately more of a stopgap—it works well for optimistic updates while avoiding excessive cache misses in regular updates, but it remains a temporary measure.


Aside from this temporary workaround, I think a better solution would be to explicitly distinguish the case using a flag.

For example, something like this

#combineResult(
  input: Array<QueryObserverResult>,
  combine: CombineFn<TCombinedResult> | undefined,
  isOptimisticUpdate = false
): TCombinedResult {
  if (combine) {
    if (
      !this.#combinedResult ||
      this.#result !== this.#lastResult ||
      (isOptimisticUpdate && input !== this.#lastInput) ||
      combine !== this.#lastCombine
    ) {
      // ...
    }
  }
}

Perhaps an approach along these lines?

But come to think of it, this method would still cause additional cache misses,,

For example, the expected values for the three tests below seem likely to increase from 3 to 5.

useQueries > should optimize combine if it is a stable reference
useQueries > should re-run combine if the functional reference changes
useQueries > should not re-run stable combine on unrelated re-render

So my final thought is that comparing lengths seems like the best choice when not considering overall mechanism modifications. What do you think?

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.

combine stable reference is not called with correct parameters
2 participants