-
-
Notifications
You must be signed in to change notification settings - Fork 861
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set order is not always maintained when modifying with produce #819
Comments
Is this a reasonable expectation? My expectation is that Sets and Maps are unordered. |
This comment was marked as spam.
This comment was marked as spam.
I'm not sure this is an issue since immer doesn't guarantee "optimal" patches, but I found some weirdness with patch output that may be related to the problematic set replacement you found. When you have a set inside of a set, and add to the deeper set, instead of a single patch reflecting the add to the deeper set, you get two patches, one removing the deeper set, and one adding it back with the new value appended.
|
We are already cloning and iterating over the Set. If we go a step further and clear it before iteration, and re-add all children during iteration, we can preserve insertion order.
🎉 This issue has been resolved in version 9.0.18 🎉 The release is available on: Your semantic-release bot 📦🚀 |
🐛 Bug Report
When adding to a Set with
produce
, the insertion order is not maintained when the original Set contains a draftable object.Link to repro
See #820 for a failing test (copied below)
To Reproduce
Run the "maintains order when adding" test in the "set drafts" section of
__tests__/base.js
.Observed behavior
After adding a second object to the Set with
produce
, it is ordered before the original first object in the Set.Expected behavior
{ id: 'b' }
should appear after{ id: 'a' }
when iterating throughnewSet
, matching the behavior of a normal mutation-based update.Debugging Observations
As mentioned above, I've only noticed this in the situation where the original Set (pre-
produce
) contains a draftable object. For example, this test passes:but the opposite does not:
Possible Root Cause
(take all of this with a grain of salt - my first time digging into the repo 😅 )
After a bit of digging, this function seems to be causing the order change during
finalize
:immer/src/utils/common.ts
Lines 131 to 138 in dc3f66c
finalizeProperty
is called on both objects (Draft of{ id: 'a' }
and vanilla object{ id: 'b' }
). On the first call, the Draft is converted back to a vanilla object and the Set value is replaced:immer/src/core/finalize.ts
Lines 130 to 131 in dc3f66c
Since Set values can't be directly updated,
set
deletes the previous version (Draft of{ id: 'a' }
) and adds the new version (vanilla object), ultimately breaking the original order.Environment
We only accept bug reports against the latest Immer version.
setUseProxies(true)
setUseProxies(false)
(ES5 only)This appears to have been introduced in v5.2.0 which contains a rewrite of the Map and Set implementations, though I've only been able to test on v5.2.1 due to #502
The text was updated successfully, but these errors were encountered: