rc.14: inside an action, a non-keyed `<Show>`'s child memo re-runs after its condition turned falsy, and the stale-value throw halts reactivity
Maintainer thường phản hồi trong vòng 1 ngà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
- 47/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Khá rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- javascript, typescript
Hướng nghiên cứu
Start by running the linked solid-flow reproduction with bunx vitest run src/core/__tests__/showStaleInAction.test.ts; compare its rc.15 failure with the rc.13 result described in REPRO.md. Trace the update ordering around the non-keyed <Show> branch and its child memo in the reproduction. Done means the child is disposed before it re-runs after when becomes undefined, and the regression test passes without halting reactivity.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
solid-js / @solidjs/[email protected] and rc.15. Regression since rc.13.
Inside an open action, a non-keyed <Show when={lookup[id]}> mounts its branch for a row the action added, and later in the same transaction its condition becomes undefined while the <For> that owns it still lists the id. The engine then re-runs a memo inside the branch (one that reads the Show's narrowed accessor) instead of disposing it first. The read throws "Attempting to access a stale value from that could possibly be undefined", and since that memo has no error boundary the whole system stops: REACTIVITY_HALTED, and no further updates are processed. On rc.13 the same sequence never throws (our DOM test asserts the added row is rendered and selected mid-action).
Traced sequence in the failing case (b is the row the action adds):
| step | <For> ids |
<Show when> for b |
b's branch memo |
|---|---|---|---|
| action adds b, selects it | ["a","b"] |
the row | mounts, runs |
| same transaction, later pass | ["a","b"] |
undefined |
RE-RUNS, throws the stale read |
Two things changed between rc.13 and rc.14 here. A derived keyed record drops a row the action added while the id list still has it; that may be an intended effect of rc.14's held writes (the plain-store writes inside the action are now held with the transaction). The re-run of a child under a falsy non-keyed <Show> is the part that looks wrong regardless: the branch should be disposed before its children run again, and a stale read in a child is turned into a crash of the whole graph.
Reproduction (headless, no DOM, no components)
Not yet reduced to @solidjs/signals alone. Inside the select step, each of its four operations is needed (removing any one avoids the crash: the index-memo read, the selected field write, the nested overlay write, the Object.assign). The surrounding pieces are a plain store over a controlled createOptimisticStore (the flow's own node list), an id list subscribed through Reflect.ownKeys, a membership-cadence index memo read untracked inside a setter, per-row createProjections (keyed mapArray) joined with a plain selection-overlay store, a keyed record projection of those rows, and an action that adds a row, then in a second setter field-writes selected on it, nests a write of the overlay entry (holding the row proxy), and Object.assigns the patch. A signals-only model with those pieces does not reproduce yet: there the added row is visible mid-action, where in the library it is held.
The repro uses solid-flow's headless flow state, rendered through solid-js <For> / <Show> with one eager memo per row. Branch repro/solid-rc14-show-stale (commit ec5977d): solid-flow next at addaf7a with the Solid packages at 2.0.0-rc.15, plus the test and a REPRO.md. Setting the Solid packages back to 2.0.0-rc.13 (steps in REPRO.md) makes the same test pass.
git clone -b repro/solid-rc14-show-stale https://github.com/dsnchz/solid-flow && cd solid-flow
bun install
bunx vitest run src/core/__tests__/showStaleInAction.test.ts # fails on rc.15: REACTIVITY_HALTED
const [nodes] = createOptimisticStore<Node[]>([node("a", 0)]);
createRoot(() => {
state = createFlowState({ nodes, edges: [] });
const view = For({
get each() { return state.store.visibleNodeIds; },
children: (id) => Show({
get when() { return state.nodeLookup.get(id); },
children: (row) => {
const label = createMemo(() => `${row().id}:${row().selected}`); // re-runs after `when` went falsy
return () => label();
},
}),
});
createRenderEffect(() => JSON.stringify(resolve(view)), () => {});
});
flush();
const addAndSelect = action(function* () {
state.commands.addNodes(node("b", 200));
state.commands.updateNode("b", { selected: true });
yield gate;
});
solid-js / @solidjs/signals |
result |
|---|---|
| 2.0.0-rc.13 | renders; no error |
| 2.0.0-rc.14 | REACTIVITY_HALTED (stale <Show> read in the row memo) |
| 2.0.0-rc.15 | REACTIVITY_HALTED (stale <Show> read in the row memo) |
On rc.15, without the updateNode call (add only), or selecting an existing row, or updating the new row's data instead of selected, nothing throws.
Where we hit it
@dschz/solid-flow composes flow commands with createOptimisticStore + action (the composition from #3085; our pin for #3665 covers this same add-then-select-in-an-action scenario). In the real component, NodeWrapper's culling memo reads the row through the Show's accessor, so a user action that adds a node and selects it (addNodes then updateNode(id, { selected: true })) before its yield freezes the whole flow on rc.14 and rc.15. We are holding our rc.15 bump on it.
- Ngôn ngữ chính
- TypeScript
- Star
- 36.1k
- Fork
- 1.1k
- Merge trung bình
- 11 giờ 45 phút
- Pull request đã merge (30 ngày)
- 329
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 solidjs/solid
-
CHEATSHEET.md and RFC 02 still recommend module-scope state for app-wide state (follow-up to #3390)Đang mở
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 86/100
Maintainer thường phản hồi trong vòng 1 ngày
-
`lazy()`: remounting an already-loaded component renders empty (or the Suspense fallback) since 1.9.14Có thể đã có người làm @itisrmk đã nhận 2 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 62/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[2.0 / next] Recovering before a held error commits throws the successful valueCó thể đã có người làm Có pull request liên kết đang mở hoặc đã được merge. Đang mở
Độ khó 4/5 1-2 ngày Mức phù hợp với người mới 48/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 42/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của solidjs/solid
Issue tương tự
-
area: aria/combobox gemini-triaged
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
angular/components#33973 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
bug priority: P2
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 84/100
Maintainer thường phản hồi trong vòng 1 ngày
-
[bug] status, list and push crash with an uncaught NotInitializedError stack trace when teamai is not initializedCó thể đã có người làm @jay23606 đã nhận hôm nay. Đang mởbug good first issue help wanted
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
Tencent/teamai-cli#1227 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[Tool]: YapĐang mở
Độ khó 1/5 1-3 giờ Mức phù hợp với người mới 62/100
withkarann/aifoxx#417 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 86/100
sindresorhus/eslint-plugin-unicorn#3921 ·
Maintainer thường phản hồi trong vòng 1 ngày