Skip to content

fix(solid-query): don't trigger Suspense when data is already cached#10592

Open
ousamabenyounes wants to merge 1 commit intoTanStack:mainfrom
ousamabenyounes:fix/issue-9955
Open

fix(solid-query): don't trigger Suspense when data is already cached#10592
ousamabenyounes wants to merge 1 commit intoTanStack:mainfrom
ousamabenyounes:fix/issue-9955

Conversation

@ousamabenyounes
Copy link
Copy Markdown
Contributor

@ousamabenyounes ousamabenyounes commented Apr 26, 2026

Summary

Fixes #9955.

When data was preloaded via ensureQueryData (e.g. from a TanStack Router loader), accessing state.data in a Suspense boundary would re-trigger the Suspense fallback even though the data was already in cache and isSuccess was true.

Root cause

In useBaseQuery.ts, the proxy data getter reads queryResource.latest?.data whenever state.data !== undefined. Per Solid's docs, .latest falls back to a read()-equivalent (and therefore triggers Suspense) when the resource has no prior resolved value.

In the preloaded-cache case, the resource's fetcher synchronously calls resolve(...) because !observerResult.isLoading, but the resource doesn't transition out of the initial pending state until the next microtask. Reading .latest inside that microtask gap suspends the component even though state.data already holds the cached value.

Fix

If the store already has data and no fetch is in-flight (!state.isFetching), return state.data directly without going through queryResource. state.isFetching is read via untrack so it doesn't widen the data subscriber's reactive deps (preserves existing reconcile / memo-churn tests).

When a fetch is in-flight, the existing queryResource.latest?.data path is preserved so background-refresh and re-mount semantics are unchanged.

Verification

  • Added regression test in packages/solid-query/src/__tests__/suspense.test.tsx that pre-populates the cache via queryClient.ensureQueryData(...), renders inside <Suspense>, and asserts the fallback never mounts. Test fails on main (Suspense fires), passes with the fix.
  • pnpm exec nx run @tanstack/solid-query:test:lib — all 310 tests pass.
  • pnpm exec nx run @tanstack/solid-query:test:types — all TS versions pass.
  • pnpm exec nx run @tanstack/solid-query:test:eslint — clean.
  • Changeset added (patch for @tanstack/solid-query).

Test plan

🤖 Generated with Claude Code
Generated by Ora Studio
Vibe coded by ousamabenyounes

Summary by CodeRabbit

  • Bug Fixes

    • Fixed an issue where Suspense would trigger unnecessarily when the requested query data was already available in the cache, including scenarios where data was preloaded using data preloading functions.
  • Tests

    • Added test coverage verifying that Suspense fallbacks do not mount when query data is already cached or preloaded, ensuring optimal performance.

Generated by Ora Studio (with Claude Code)
Vibe coded by Ben Younes Ousama

When data was preloaded via `ensureQueryData` (e.g. from a router loader),
the proxy `data` getter read `queryResource.latest`, which falls back to a
suspending read while the resource is in its initial pending state, even
though the fetcher had already synchronously resolved with cached data.

If the store already has data and no fetch is in-flight, return `state.data`
directly. `state.isFetching` is read via `untrack` so it doesn't widen the
data subscriber's reactive deps.

Fixes TanStack#9955
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

📝 Walkthrough

Walkthrough

This PR fixes a Suspense issue in Solid Query where Suspense was unnecessarily triggered when accessing preloaded query data via ensureQueryData. The fix modifies the data property getter in useBaseQuery.ts to check if fetching is in-flight before accessing the Solid resource, preventing reactive tracking leakage.

Changes

Cohort / File(s) Summary
Changeset Documentation
.changeset/solid-query-suspense-ensure-data.md
Patch release note documenting the fix to prevent Suspense from being triggered when data is already available in cache, including scenarios with ensureQueryData preloading.
Test Addition
packages/solid-query/src/__tests__/suspense.test.tsx
New test case that preloads query data using ensureQueryData with staleTime: Infinity, then verifies the component renders without mounting the Suspense fallback.
Core Fix
packages/solid-query/src/useBaseQuery.ts
Modified data property getter to conditionally skip resource access when data is present and no fetch is in-flight, preventing isFetching tracking from leaking into the data subscriber and triggering unnecessary Suspense.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A query once preloaded with care,
Would trigger suspense in the air,
But now with a check,
No tracking to wreck,
The data flows freely and fair! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main fix: preventing Suspense from being triggered when data is already cached.
Linked Issues check ✅ Passed The PR successfully addresses all requirements from issue #9955: it fixes the bug where accessing data after confirming isSuccess triggers Suspense when loaded via ensureQueryData, implements the correct fix, and includes regression tests.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing issue #9955: the fix in useBaseQuery.ts, regression test, and changeset are all in-scope for the stated objective.
Description check ✅ Passed PR description is comprehensive and follows the template structure with detailed root cause analysis, fix explanation, and thorough verification steps.

✏️ 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.

@nx-cloud
Copy link
Copy Markdown

nx-cloud Bot commented Apr 26, 2026

View your CI Pipeline Execution ↗ for commit fe12586

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

☁️ Nx Cloud last updated this comment at 2026-04-26 08:28:38 UTC

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 26, 2026

More templates

@tanstack/angular-query-experimental

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

@tanstack/eslint-plugin-query

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

@tanstack/preact-query

npm i https://pkg.pr.new/@tanstack/preact-query@10592

@tanstack/preact-query-devtools

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

@tanstack/preact-query-persist-client

npm i https://pkg.pr.new/@tanstack/preact-query-persist-client@10592

@tanstack/query-async-storage-persister

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

@tanstack/query-broadcast-client-experimental

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

@tanstack/query-core

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

@tanstack/query-devtools

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

@tanstack/query-persist-client-core

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

@tanstack/query-sync-storage-persister

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

@tanstack/react-query

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

@tanstack/react-query-devtools

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

@tanstack/react-query-next-experimental

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

@tanstack/react-query-persist-client

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

@tanstack/solid-query

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

@tanstack/solid-query-devtools

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

@tanstack/solid-query-persist-client

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

@tanstack/svelte-query

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

@tanstack/svelte-query-devtools

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

@tanstack/svelte-query-persist-client

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

@tanstack/vue-query

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

@tanstack/vue-query-devtools

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

commit: fe12586

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.

Solid Suspense is triggered on data access after checking isSuccess when loaded by ensureQueryData

1 participant