diff --git a/.changeset/thin-badgers-move.md b/.changeset/thin-badgers-move.md new file mode 100644 index 000000000..a2be269f6 --- /dev/null +++ b/.changeset/thin-badgers-move.md @@ -0,0 +1,5 @@ +--- +"@solidjs/signals": patch +--- + +update primitive store array mappings diff --git a/packages/solid-signals/src/store/reconcile.ts b/packages/solid-signals/src/store/reconcile.ts index 0aa5d564e..7b3737513 100644 --- a/packages/solid-signals/src/store/reconcile.ts +++ b/packages/solid-signals/src/store/reconcile.ts @@ -137,9 +137,11 @@ function applyStateFast(next: any, target: any, keyFn: (item: NonNullable) } else if (next.length) { for (let i = 0, len = next.length; i < len; i++) { const item = previous[i]; - isWrappable(item) - ? applyState(next[i], wrap(item, target), keyFn) - : target[STORE_NODE][i] && setSignal(target[STORE_NODE][i], next[i]); + if (isWrappable(item)) applyState(next[i], wrap(item, target), keyFn); + else { + if (item !== next[i]) changed = true; + target[STORE_NODE][i] && setSignal(target[STORE_NODE][i], next[i]); + } } } @@ -279,9 +281,11 @@ function applyStateSlow(next: any, target: any, keyFn: (item: NonNullable) } else if (next.length) { for (let i = 0, len = next.length; i < len; i++) { const item = getOverrideValue(previous, override, i as any, optOverride); - isWrappable(item) - ? applyState(next[i], wrap(item, target), keyFn) - : target[STORE_NODE][i] && setSignal(target[STORE_NODE][i], next[i]); + if (isWrappable(item)) applyState(next[i], wrap(item, target), keyFn); + else { + if (item !== next[i]) changed = true; + target[STORE_NODE][i] && setSignal(target[STORE_NODE][i], next[i]); + } } } diff --git a/packages/solid-signals/tests/maparray-store-nonkeyed.test.ts b/packages/solid-signals/tests/maparray-store-nonkeyed.test.ts index 2630058cd..5e4aad7e8 100644 --- a/packages/solid-signals/tests/maparray-store-nonkeyed.test.ts +++ b/packages/solid-signals/tests/maparray-store-nonkeyed.test.ts @@ -1,5 +1,34 @@ import { describe, expect, test } from "vitest"; -import { createRoot, createStore, mapArray, flush } from "../src/index.js"; +import { createRoot, createSignal, createStore, mapArray, flush } from "../src/index.js"; + +describe("mapArray backed by derived store arrays", () => { + test("updates when same-length primitive array items are replaced", () => { + let setIssue!: (issue: number) => void; + let mapped!: () => string[]; + + const dispose = createRoot(dispose => { + const [issue, set] = createSignal(0); + const [comments] = createStore( + () => [`issue ${issue()} comment 0`, `issue ${issue()} comment 1`], + [] + ); + setIssue = set; + mapped = mapArray( + () => comments, + comment => comment + ); + return dispose; + }); + + expect(mapped()).toEqual(["issue 0 comment 0", "issue 0 comment 1"]); + + setIssue(1); + flush(); + + expect(mapped()).toEqual(["issue 1 comment 0", "issue 1 comment 1"]); + dispose(); + }); +}); describe("mapArray keyed:false backed by a store (#2687)", () => { // Regression: mapArray's internal owner is a Root, so untracked store-proxy