fix(inventory): stop unseen-tracker mutating shared state arrays in place

resetItems/removeUnseen/the UnseenItemsEvent handler each did `new Map(prevValue)`
(a shallow copy) then spliced/pushed the per-category array returned by
`.get(category)` — the SAME array reference still held by the previous Map. That
mutates state outside React's data flow (breaks under StrictMode double-invoke and
any updater replay). resetItems additionally did `splice(existing.indexOf(id), 1)`
with no guard, so an id not present (indexOf === -1) spliced off the wrong LAST
element. Replace each in-place splice/push with a cloned array set back on the new
Map (filter for removals, spread+push for the merge).
This commit is contained in:
simoleo89
2026-06-13 15:58:27 +02:00
parent 93baedf206
commit 9cc9ef86c0
@@ -63,7 +63,10 @@ const useInventoryUnseenTrackerState = () =>
const newValue = new Map(prevValue);
const existing = newValue.get(category);
if(existing) for(const itemId of itemIds) existing.splice(existing.indexOf(itemId), 1);
// Replace the per-category array instead of splicing the one still
// referenced by the previous Map, and filter (an absent id used to
// splice(indexOf=-1) and drop the wrong last element).
if(existing) newValue.set(category, existing.filter(id => !itemIds.includes(id)));
sendResetItemsMessage(category, itemIds);
@@ -90,9 +93,9 @@ const useInventoryUnseenTrackerState = () =>
const newValue = new Map(prevValue);
const items = newValue.get(category);
const index = items.indexOf(itemId);
if(index >= 0) items.splice(index, 1);
// Clone the array rather than splicing the one shared with prevValue.
if(items && items.indexOf(itemId) >= 0) newValue.set(category, items.filter(id => id !== itemId));
return newValue;
});
@@ -108,18 +111,15 @@ const useInventoryUnseenTrackerState = () =>
for(const category of parser.categories)
{
let existing = newValue.get(category);
if(!existing)
{
existing = [];
newValue.set(category, existing);
}
// Clone the existing array so we never push into the one still
// referenced by the previous (shallow-copied) Map.
const merged = [ ...(newValue.get(category) ?? []) ];
const itemIds = parser.getItemsByCategory(category);
for(const itemId of itemIds) ((existing.indexOf(itemId) === -1) && existing.push(itemId));
for(const itemId of itemIds) if(merged.indexOf(itemId) === -1) merged.push(itemId);
newValue.set(category, merged);
}
return newValue;