fix: preserve structural sharing for no-op array-methods calls - #1289
Open
maximilliangrand wants to merge 1 commit into
Open
fix: preserve structural sharing for no-op array-methods calls#1289maximilliangrand wants to merge 1 commit into
maximilliangrand wants to merge 1 commit into
Conversation
The enableArrayMethods() plugin routed every mutating array method through executeArrayMethod, which unconditionally called markChanged. As a result calls that change nothing - push()/unshift() with no arguments (e.g. the common draft.list.push(...items) with an empty items), splice(i, 0), and pop()/shift() on an empty array - produced a new state reference, breaking the structural-sharing guarantee that native Immer keeps (produce returning the base when nothing changed). Detect these no-ops in O(1) and skip marking the array changed, so the producer returns the base and emits no patches, matching core behavior. Signed-off-by: maximilliangrand <214999687+maximilliangrand@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
With
enableArrayMethods()enabled, mutating array methods that change nothing still produce a new state reference, breaking Immer's structural-sharing guarantee that a change-free producer returns the base.Same for
splice(i, 0), andpop()/shift()on an empty array. The common real-world trigger isdraft.list.push(...incoming)whenincominghappens to be empty, which silently invalidates memoization and forces re-renders. Native Immer (plugin disabled) returns the base in all these cases.Cause
The plugin routes every mutating method through
executeArrayMethod, which callsmarkChangedunconditionally, bypassing the no-op detection that core'ssettrap performs.Fix
Detect these no-ops in O(1) and skip marking the array changed, so the producer returns the base and emits no patches, matching core behavior. Real mutations and their patches are unchanged.
sort()/reverse()are left untouched: they are genuine reorder operations where cheap no-op detection isn't possible.Verification
prettier --checkclean.