Repository navigation
Version 1.6.0
·
5 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
What's Changed
Added
map()/forEach()onMutableListandDerivedList(src/nodes/list.ts,src/nodes/collection.ts): Both visit every item in list order, passing each item's signal and its stable string key —map<R>(callbackfn: (item: S, key: string) => R): R[]andforEach(callbackfn: (item: S, key: string) => void): void, with the parameter order followingMap.prototype.forEach((value, key) => …). UndercreateList(…, { createItem: createStore }),Sis the item'sMutableStore<T>.mapreturns a plain array snapshot, not a signal — reactive mapping over values remainsderiveList's job. Tracking is identical to[Symbol.iterator](ADR-0015 class): one structural subscription, no internalsignal.get(), so reads inside the callback track as usual. Amap/forEach-only effect re-runs on add, remove, reorder, andreplace(key, v);byKey(k).set(v)re-runs it only afterlist.get()has linked the item signal to the list node. The key array is snapshotted before traversal, so a callback that mutates the list does not change the current pass. Both methods are declared on theMutableList/DerivedListtypes, so the deprecatedList/Collectionaliases inherit them. Motivated by keyed JSX list rendering, where a compiler lowers.map((item, key) => …)to a keyed reconcile over item signals. See ADR-0019.
Fixed
- Per-item signals of a per-item
deriveList(source, fn)gated propagation on===, so a fresh deep-equal derived item over-notified structural subscribers (src/nodes/collection.ts): Previously, the per-itemMemo(sync callback) and per-itemTask(async callback) were built without anequalsoption and fell back to strict equality — the only per-slice derivation path that did, against ADR-0018's rule that per-sliceequalsstops propagation for an unchanged property or item (deriveStore's per-property memos, the keyed adapter's item signals, and mutable list item states all default toDEEP_EQUALITY). When the callback returned a fresh but deep-equal object — e.g.deriveList(users, u => ({ name: u.name }))while an unrelated field of the source item changed — the===gate failed, the derived node rebuilt its array, and every structural subscriber (iterator,map,forEach,get()) re-ran although the derived content was unchanged. Now both per-item signals useequals: DEEP_EQUALITY, so a deep-equal recompute stops at the per-item signal and only a genuine derived-content change reaches the node. Effects that read derived values observe no content difference; only object-identity checks on derived items could distinguish the old behavior, and keys — not object references — are identity in this library. The derived node's own element-identity array comparison is unchanged: it only ever sees arrays whose element references genuinely changed.
Full Changelog: v1.5.2...v1.6.0