fix(solid-query): don't trigger Suspense when data is already cached#10592
fix(solid-query): don't trigger Suspense when data is already cached#10592ousamabenyounes wants to merge 1 commit intoTanStack:mainfrom
Conversation
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
📝 WalkthroughWalkthroughThis PR fixes a Suspense issue in Solid Query where Suspense was unnecessarily triggered when accessing preloaded query data via Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
View your CI Pipeline Execution ↗ for commit fe12586
☁️ Nx Cloud last updated this comment at |
Summary
Fixes #9955.
When data was preloaded via
ensureQueryData(e.g. from a TanStack Router loader), accessingstate.datain a Suspense boundary would re-trigger the Suspense fallback even though the data was already in cache andisSuccesswastrue.Root cause
In
useBaseQuery.ts, the proxydatagetter readsqueryResource.latest?.datawheneverstate.data !== undefined. Per Solid's docs,.latestfalls back to aread()-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 initialpendingstate until the next microtask. Reading.latestinside that microtask gap suspends the component even thoughstate.dataalready holds the cached value.Fix
If the store already has
dataand no fetch is in-flight (!state.isFetching), returnstate.datadirectly without going throughqueryResource.state.isFetchingis read viauntrackso 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?.datapath is preserved so background-refresh and re-mount semantics are unchanged.Verification
packages/solid-query/src/__tests__/suspense.test.tsxthat pre-populates the cache viaqueryClient.ensureQueryData(...), renders inside<Suspense>, and asserts the fallback never mounts. Test fails onmain(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.patchfor@tanstack/solid-query).Test plan
🤖 Generated with Claude Code
Generated by Ora Studio
Vibe coded by ousamabenyounes
Summary by CodeRabbit
Bug Fixes
Tests
Generated by Ora Studio (with Claude Code)
Vibe coded by Ben Younes Ousama