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
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 45/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- typescript
- Lĩnh vực
- frontend
Hướng nghiên cứu
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.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
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).
- Ngôn ngữ chính
- TypeScript
- Star
- 50.4k
- Fork
- 4.2k
- Merge trung bình
- 7 giờ 29 phút
- Pull request đã merge (30 ngày)
- 393
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của TanStack/query
-
solid-query: STRICT_READ_UNTRACKED on Solid 2 — client()/options() read in component body (useMutation, useBaseQuery)Có thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
TanStack/query#11358 · 2 bình luận · 1 reaction ·
Maintainer thường phản hồi trong vòng 1 ngày
-
solid-query: switching the queryClient accessor strands the new client's cache (subscription stays on the old observer)Có thể đã có người làm @MaNaN1803 đã nhận 76 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
TanStack/query#11106 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
restoreQueries and persisterGc throw on malformed persisted entriesCó thể đã có người làm @VGontier-cmd đã nhận 1 ngày trước. Đang mở
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
setQueryData: NoInfer loses discriminated-union members when spreading a narrowed updater valueCó thể đã có người làm @iosayin đã nhận 3 ngày trước. Đang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 55/100
Maintainer thường phản hồi trong vòng 1 ngày
-
setQueryData updater loses discriminated-union fields when spreading inferred NoInfer dataCó thể đã có người làm @boriskozak đã nhận 3 ngày trước. Đang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 68/100
TanStack/query#11794 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của TanStack/query
Issue tương tự
-
refactor
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
tomnewport/memprot-topo#55 ·
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
WalletConnect/walletconnect-monorepo#7368 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
enhancement
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
BU-Spark/se-chem-apll#47 ·
-
embed: handleTurboSignMessage header comment says the signing page posts to '*' (it never does)Đang mởdocumentation
Độ khó 2/5 Dưới một giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 Nửa ngày Mức phù hợp với người mới 70/100
udistrital/paginaweb_root#23 ·