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
维护者通常 1 天内回复
还没有人认领这个 Issue。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 47/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 活跃
- 技术栈
- javascript, typescript
调研方向
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.
由索引模型根据 Issue 内容生成。
描述
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.
- 主要语言
- TypeScript
- 星标
- 36.1k
- 派生
- 1.1k
- 平均合并
- 11 小时 37 分钟
- 30 天内合并 PR
- 344
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
solidjs/solid 的其他 Issue
-
`lazy()`: remounting an already-loaded component renders empty (or the Suspense fallback) since 1.9.14可能已有人在做 @itisrmk 于 2 天前认领。 未关闭1.x
难度 2/5 1-3 小时 新手友好度 62/100
维护者通常 1 天内回复
-
[2.0 rc.15 + next] For row lifecycle cleanup inherits the list computation and halts on a shared-state write可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭
难度 4/5 3-5 天 新手友好度 51/100
维护者通常 1 天内回复
-
难度 4/5 1-2 天 新手友好度 48/100
维护者通常 1 天内回复
-
难度 4/5 3-5 天 新手友好度 35/100
维护者通常 1 天内回复
-
`createRoot`'s dispose function keeps `fn` alive, so `<For>`/`<Index>` rows retain removed list items可能已有人在做 @boombang 于 4 天前认领。 未关闭1.x
难度 4/5 1-2 天 新手友好度 45/100
维护者通常 1 天内回复
相似的 Issue
-
docs(api): openapi.yaml still documents gif-tools optimize colors as 2-256 instead of 2, 4, 16, 256未关闭area: backend documentation priority: low
难度 2/5 1-3 小时 新手友好度 84/100
snapotter-hq/SnapOtter#2919 ·
维护者通常 1 天内回复
-
accepted :+1: bug db/redis
难度 2/5 1-3 小时 新手友好度 76/100
beekeeper-studio/beekeeper-studio#4882 · 1 条评论 ·
维护者通常 1 天内回复
-
ready-for-triage
难度 2/5 1-3 小时 新手友好度 72/100
konflux-ci/konflux-ui#1630 · 1 条评论 ·
维护者通常 2 天内回复
-
难度 2/5 1-3 小时 新手友好度 67/100
ahmedkhaleel2004/gitdiagram#233 ·
-
难度 2/5 1-3 小时 新手友好度 72/100
simkimsia/netlify-axi#19 ·
维护者通常 1 天内回复