solid-query: EFFECT_RELAY_TEAR on Solid 2 when a query key changes — useBaseQuery relays the result through a version signal written from a render effect
Les mainteneurs répondent en général sous 1 jour
Personne n'a encore pris cette issue.
Évaluation
- Difficulté
- 4/5
- Temps estimé
- 3-5 jours
- Accessibilité débutants
- 45/100
- Type d'issue
- Bug
- Clarté
- Clairement spécifiée
- Activité
- Active
- Stack technique
- typescript
- Domaine
- frontend
Piste de recherche
The adapter's useBaseQuery (the payload points at build/index.js) wires createRenderEffect(() => defaultedOptions(), opts => observer.setOptions(opts)), then relays cache events into a version signal read by query. Start by reproducing the key switch with the issue's captureArtifact snippet under vitest/jsdom and confirming EFFECT_RELAY_TEAR. Trace whether the observer result can be derived as a memo or projection of the current options instead of a counter written from onCacheEvent; done means the diagnostic no longer fires and query.data shows the new key's value in the same flush.
Rédigé par le modèle d'indexation à partir du texte de l'issue.
Description
Describe the bug
With Solid 2 ([email protected]) and @tanstack/[email protected] (the useBaseQuery code is identical in 6.0.0-rc.5), switching the query key of a useQuery logs a reactivity diagnostic from @solidjs/[email protected]:
[EFFECT_RELAY_TEAR] memo "computed" ran twice for one write of "tariff": once in the flush where "tariff" changed,
and again after effect "effect" relayed it by writing "signal" — the first frame showed the new "tariff" with the stale "signal".
If "signal" is computed from what the effect reads, make it a memo so readers get it in the same flush;
if the write reads something outside the graph (layout, time), the tear is the cost of measuring.
Owner path: <QueryClientProvider> › <provider> › computed › <Price> › computed — the only user code is a createMemo reading query.data. One diagnostic per useQuery instance whose key changed (a screen with five queries logs five).
Solid 2 dev builds treat these diagnostics as actionable (the console is expected to stay clean), so every app that derives anything from query.data and ever changes a key gets a warning it cannot fix on its side.
Where it comes from
useBaseQuery (build/index.js):
createRenderEffect(
() => defaultedOptions(),
(opts) => observer.setOptions(opts)
);
const [version, setVersion] = createSignal(0, { ownedWrite: true });
const onCacheEvent = (event) => {
if (event.query.queryHash === untrack(defaultedOptions).queryHash || event.query.queryHash === latestHash) {
setVersion((v) => v + 1);
}
};
...
const query = () => {
version();
return lookupQuery();
};
When the key changes, defaultedOptions is recomputed in the same flush as the key signal; readers of query.data see the new options with the old observer result, then the render effect calls observer.setOptions, the cache event bumps version, and every memo downstream recomputes a second time. That is exactly the "effect relays a derived value by writing a signal" pattern the diagnostic describes: version is derived from what the effect reads, so the first frame is torn.
Your minimal, reproducible example
import { captureArtifact } from '@solidjs/diagnostics';
import { render } from '@solidjs/testing-library';
import { QueryClient, QueryClientProvider, useQuery } from '@tanstack/solid-query';
import { createMemo, createSignal, flush } from 'solid-js';
function Price(props: { tariff: string }) {
const query = useQuery(() => ({ queryKey: ['price', props.tariff], queryFn: async () => props.tariff.length }));
const doubled = createMemo(() => (query.data ?? 0) * 2);
return <span>{doubled()}</span>;
}
const client = new QueryClient({ defaultOptions: { queries: { staleTime: Infinity, retry: false } } });
client.setQueryData(['price', 'base'], 1);
client.setQueryData(['price', 'site'], 2);
const [tariff, setTariff] = createSignal('base');
const { artifact } = await captureArtifact(async () => {
const screen = render(() => (
<QueryClientProvider client={client}>
<Price tariff={tariff()} />
</QueryClientProvider>
));
flush();
setTariff('site'); // key change
flush();
await new Promise((r) => setTimeout(r, 30));
flush();
screen.unmount();
}, { scenario: 'useQuery key switch', attribution: true });
console.log(artifact.diagnostics.map((e) => e.code)); // ['EFFECT_RELAY_TEAR']
Both keys are already in the cache, so no fetch is involved — the second recompute is purely the version relay.
Steps to reproduce
- Mount a component with
useQuerywhose key depends on a signal, and acreateMemoreadingquery.data. - Change the signal (with
@solidjs/diagnosticscapturing, attribution on). - Observe
EFFECT_RELAY_TEARfor the memo.
Expected behavior
Changing a query key should produce one consistent frame: the result for the new key arrives in the same flush as the key (e.g. the observer result derived as a memo / projection of the options instead of being relayed through a counter signal written from a cache subscription), or the diagnostic should not fire for useQuery consumers.
Platform
- OS: macOS 13
- Browser: Brave (Chromium), also reproduces under vitest + jsdom
[email protected],@solidjs/[email protected]@tanstack/[email protected](sameuseBaseQueryin rc.5)
TanStack Query adapter
solid-query
TanStack Query version
6.0.0-rc.4 / 6.0.0-rc.5
TypeScript version
7.0
Additional context
Related: #11358 (STRICT_READ_UNTRACKED in the same adapter under Solid 2 diagnostics).
- Langage dominant
- TypeScript
- Étoiles
- 50.4k
- Forks
- 4.2k
- Merge moyen
- 11 h 33 min
- PR mergées (30 j)
- 421
Préparer son environnement
- Aucun Dockerfile ni fichier Docker Compose
- Propose un modèle de pull request
- Lire le guide de contribution
Par où commencer
- Lisez l'issue en entier, puis le guide de contribution du projet.
- Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
- Forkez le dépôt et travaillez sur une branche.
- Ouvrez une pull request qui référence le numéro de l'issue.
Autres issues de TanStack/query
-
solid-query: STRICT_READ_UNTRACKED on Solid 2 — client()/options() read in component body (useMutation, useBaseQuery)Peut-être à nouveau libre Une pull request pour cette issue a été fermée sans être fusionnée. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
TanStack/query#11358 · 2 commentaires · 1 réaction ·
Les mainteneurs répondent en général sous 1 jour
-
solid-query: switching the queryClient accessor strands the new client's cache (subscription stays on the old observer)Peut-être pris @MaNaN1803 l’a pris il y a 74 jours. Ouverte
Difficulté 2/5 1-3 heures Accessibilité débutants 84/100
TanStack/query#11106 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
setQueryData: NoInfer loses discriminated-union members when spreading a narrowed updater valuePeut-être pris @iosayin l’a pris il y a 1 jour. Ouverte
Difficulté 4/5 3-5 jours Accessibilité débutants 55/100
Les mainteneurs répondent en général sous 1 jour
-
setQueryData updater loses discriminated-union fields when spreading inferred NoInfer dataPeut-être pris @boriskozak l’a pris il y a 1 jour. Ouverte
Difficulté 4/5 3-5 jours Accessibilité débutants 68/100
TanStack/query#11794 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
[vue-query]: UseMutationReturnType default names unexported MutationResult (TS2883) 🤖🤖🤖Peut-être pris Une pull request liée à cette issue est ouverte ou déjà fusionnée. Ouverte
Difficulté 3/5 1-2 jours Accessibilité débutants 68/100
Les mainteneurs répondent en général sous 1 jour
Toutes les issues de TanStack/query
Issues similaires
-
perf(core): getComments() runs the approved count and the comment list as two sequential queriesOuvertearea/core bot:bug bot:working
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
emdash-cms/emdash#3905 · 2 commentaires ·
Les mainteneurs répondent en général sous 1 jour
-
community first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
Difficulté 1/5 Moins d'une heure Accessibilité débutants 90/100
lingdojo/kana-dojo#31728 · 1 commentaire · 5 réactions ·
Les mainteneurs répondent en général sous 1 jour
-
selective-claw: freshTailTurns=0 keeps ALL turns verbatim and summarizes none (slice(-0) === slice(0))Peut-être pris @zjncs l’a pris aujourd’hui. Ouvertecomponent:tokenless
Difficulté 2/5 1-3 heures Accessibilité débutants 80/100
agentic-os-org/ANOLISA#6112 · 1 commentaire ·
Les mainteneurs répondent en général sous 1 jour
-
bug needs triage
Difficulté 2/5 1-3 heures Accessibilité débutants 75/100
rjsf-team/react-jsonschema-form#5439 ·
Les mainteneurs répondent en général sous 1 jour
-
enhancement
Difficulté 2/5 1-3 heures Accessibilité débutants 76/100
Les mainteneurs répondent en général sous 1 jour