[2.0] IMMUTABLE_UPDATE_IN_STORE false positive when an in-place `splice` shifts the next item into the removed index
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 55/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- javascript, typescript
- 領域
- backend, testing-qa
調査の方向性
Start in packages/signals/src/store/store.ts at reportReplacedContainers and trace how array writes from splice are checked; compare that with the array branch’s oldItems identity set. Read packages/signals/src/core/attribution.ts for checkImmutableUpdate, then reproduce the case in a dev build and check that moving an existing item emits no report while replacing it with a fresh similar object still does.
索引モデルが issue の本文から書いたものです。
説明
Version: solid-js / @solidjs/signals 2.0.0-rc.18, dev build. The relevant code is unchanged on next (4ea2f4986).
Description
Removing an item from a store array with an in-place splice (the repair the diagnostic itself recommends for arrays) can report IMMUTABLE_UPDATE_IN_STORE for the index the next item shifts into. This happens when the removed item and the one after it share at least half of their leaf values, for example two lines of the same product that differ only in one field.
No container was copied. After the splice, index 0 holds the object that was already at index 1.
Reproduction
Run in a dev build with the diagnostics observed (I used captureArtifact from @solidjs/diagnostics in a vitest jsdom test; the same message appears in the dev console):
import { createStore, flush } from 'solid-js'
const [, setState] = createStore({
items: [
{ id: 'a', product: 'p1', name: 'Pancakes', variant: 'meat', quantity: 2 },
{ id: 'b', product: 'p1', name: 'Pancakes', variant: 'cheese', quantity: 2 },
],
})
setState((draft) => {
draft.items.splice(0, 1)
})
flush()
No reader or effect is needed.
Actual
[IMMUTABLE_UPDATE_IN_STORE] "store.items.0" was replaced with a fresh object whose leaves are mostly the same values (3 of 5 unchanged, 2 changed) — a spread-copy update. The store already tracks leaves; a new container makes every reader of "store.items.0" re-run for the few that moved. Instead, assign the leaf on the draft (`store.items.0.<key> = …`) so only readers of that key re-run. For data arriving from outside (a fetch result), merge it with reconcile(data, key)(store.items.0).
Control: if the two items share fewer than half of their leaves (for example { id: 'b', product: 'p2', name: 'Soup', variant: 'cheese', quantity: 5 } as the second item), nothing is reported.
Expected
No report. The object now at items[0] is an item that was already in the same array before the write, so the write moved an existing item and did not replace it with a fresh copy. The suggested repair ("assign the leaf on the draft") does not apply here.
Code location
reportReplacedContainers in packages/signals/src/store/store.ts. For each written key it compares the leaves of the old and new object at that key. For an array index written by splice, the new value is the shifted sibling, so the leaf census compares two different existing items and checkImmutableUpdate (packages/signals/src/core/attribution.ts) sees "mostly the same values".
A possible fix is to skip the report when the new value at an array index is unwrapValue-identical to one of the old array's items (the same identity set the array branch already builds for oldItems), since that is a move and not a fresh container.
- 主要言語
- TypeScript
- スター
- 36.2k
- フォーク
- 1.1k
- 平均マージ
- 11時間 5分
- マージ済み PR(30日)
- 353
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
solidjs/solid のほかの issue
-
`lazy()`: remounting an already-loaded component renders empty (or the Suspense fallback) since 1.9.14対応中かも @itisrmk が 9 日前に担当しました。 オープン1.x
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 48/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 1〜2日 初心者へのやさしさ 48/100
メンテナーはふだん 1 日以内に返信
-
enhancement
難易度 5/5 1週間以上 初心者へのやさしさ 35/100
メンテナーはふだん 1 日以内に返信
-
`createRoot`'s dispose function keeps `fn` alive, so `<For>`/`<Index>` rows retain removed list items対応中かも @boombang が 12 日前に担当しました。 オープン1.x
難易度 4/5 1〜2日 初心者へのやさしさ 45/100
メンテナーはふだん 1 日以内に返信
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 79/100
-
難易度 2/5 1〜3時間 初心者へのやさしさ 79/100
galaxyproject/loom#616 ·
メンテナーはふだん 1 日以内に返信
-
e2e-failure ready-to-code
難易度 2/5 1〜3時間 初心者へのやさしさ 79/100
redhat-developer/rhdh-plugin-export-overlays#4580 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1〜3時間 初心者へのやさしさ 84/100
eknowledger/toolbench#266 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
devdotfast/whiteboard#1415 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信