I'm looking for some clarity on the pitfall item regarding state being a unidirectional tree. If clarity can be found, I'd be happy to make a PR to update.
It says that no object must appear twice and no circular dependencies. By "object" does it mean a JavaScript Object or does it mean all "things", aka. strings, numbers, booleans, arrays, objects, maps, etc.?
A common pattern I use in ImmutableJS is to hold identical objects in different parts of state, eg. users and selectedUsers might be a subset. Would this break Immer?
I ask because I often deal with hundreds of thousands of geographic elements, so alternative methods (eg. holding a list of which ones are selected by ID) have a performance cost when trying to evaluate the selection for usage.
Thank you!
Object means: anything mutable
Not using a tree will result in your object existing twice instead of once
in the tree as soon as you modify it
Afaik immutable JS has this very same limitation. I might be mistaken, if
so, it would be great if you could show the difference in a small sandbox
Op di 28 mei 2019 03:04 schreef Andrew Blakey notifications@github.com:
I'm looking for some clarity on the pitfall item regarding state being a
unidirectional tree. If clarity can be found, I'd be happy to make a PR to
update.It says that no object must appear twice and no circular dependencies. By
"object" does it mean a JavaScript Object or does it mean all "things",
aka. strings, numbers, booleans, arrays, objects, maps, etc.?A common pattern I use in ImmutableJS is to hold identical objects in
different parts of state, eg. users and selectedUsers might be a subset.
Would this break Immer?I ask because I often deal with hundreds of thousands of geographic
elements, so alternative methods (eg. holding a list of which ones are
selected by ID) have a performance cost when trying to evaluate the
selection for usage.Thank you!
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/immerjs/immer/issues/374?email_source=notifications&email_token=AAN4NBB5DUDJKZPU3A4VZYDPXSAILA5CNFSM4HP67CAKYY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4GWDRI6Q,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAN4NBHB45YVGBCIVEWL5GLPXSAILANCNFSM4HP67CAA
.
Thanks for the response. I'm going to guess that there's semantic confusion on my part.
Here's an example with ImmutableJS: https://jsfiddle.net/cnr5vL13/1/
Notice that I have the Immutable Map sara in multiple places in my state. When I update bob, Sara ends up existing in multiple places (current and previous edits). These aren't copies, they have the same identity.
I think I'm trying to better understand how to safely leverage copy-on-write in Immer so that I can do something like the above example. Based on my reading of the Pitfalls, I think it means that if I wanted to do the above, I would have to deepCopy each entity before setting it onto previous edits.
Immer structurally shares things in the next state with the current state
if they didn't modify. So I think it just pretty much does what you are
looking for, and that the conceptual problem you are describing is just a
different one than the one you are demonstrating / are trying to achieve.
If that isn't the case, please demonstrate the problem you are having in an
immer example. Otherwise, please close the issue :)
On Tue, May 28, 2019 at 1:51 PM Andrew Blakey notifications@github.com
wrote:
Thanks for the response. I'm going to guess that there's semantic
confusion on my part.Here's an example with ImmutableJS: https://jsfiddle.net/cnr5vL13/1/
Notice that I have the Immutable Map sara in multiple places in my state.
When I update bob, Sara ends up existing in multiple places (current and
previous edits). These aren't copies, they have the same identity.I think I'm trying to better understand is how to safely leverage
copy-on-write in Immer so that I can do something like the above example.
Based on my reading of the Pitfalls, I think it means that if I wanted
to do the above, I would have to deepCopy each entity before setting it
onto previous edits.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/immerjs/immer/issues/374?email_source=notifications&email_token=AAN4NBAHPRXNARLN4IPQ5ZDPXUMFLA5CNFSM4HP67CAKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWL37RQ#issuecomment-496484294,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAN4NBGTVHVHRDC2MB4NGWTPXUMFLANCNFSM4HP67CAA
.
That's good to know. And again, apologies if this is just me misunderstanding things. I tried to find an Immer community to chat this out but couldn't.
What I'm curious about is how I have the same object in multiple places in the current state. The history (undo/redo) example above is trying to illustrate a reason why unchanged elements might appear many times (in each version in the history array).
Let me try again with immer:
import produce from 'immer';
let state = {
history: [],
robots: {
bob: {
isOnline: false
},
sue: {
isOnline: false
}
}
};
function setOnline(robot, isOnline) {
const newState = produce(state, draft => {
// keep hisory of the robots branch so we can `undo`.
draft.history.push(state.robots); // Or should I be pushing draft.robots?
// Update the new state.
draft.robots[robot][isOnline] = isOnline
})
state = newState;
}
setOnline('bob', true)
setOnline('bob', false)
setOnline('bob', true)
setOnline('bob', false)
At this point history has 4 copies. If we walked through them we'd see bob's state changing, but sue never changes. I expect sue's 5 objects to be the same object (identity), because this respects copy-on-write. Ie. we're not making copies of elements that aren't changing. The problem is that this means the same object appears many times in the state tree, which violates the listed pitfall.
I think it's "fine" to have the same object appear multiple times in the state tree. Just don't expect it to be synchronized. For example, if you edit the object in one place, it won't be updated in the other places it appears. This happens because we create a new "draft" proxy based on the property path, not the object identity.
We should probably add some unit tests for this, just so we can prove the undefined behavior to some degree.
Can you just try it first, and then raise issues?
Op do 30 mei 2019 13:10 schreef Andrew Blakey notifications@github.com:
That's good to know. But what I'm curious about is how I have the same
object in multiple places in the current state. The history (undo/redo)
example above is trying to illustrate a reason why unchanged elements might
appear many times (in each version in the history array).Let me try again with immer:
import produce from 'immer';
let state = {
history: [],
robots: {
bob: {
isOnline: false
},
sue: {
isOnline: false
}
}
};
function setOnline(robot, isOnline) {
const newState = produce(state, draft => {
// keep hisory of the robots branch so we canundo.
draft.history.push(state.robots); // Or should I be pushing draft.robots?// Update the new state. draft.robots[robot][isOnline] = isOnline }) state = newState;}
setOnline('bob', true)setOnline('bob', false)setOnline('bob', true)setOnline('bob', false)
// At this point history has 4 copies. If we walked through them we'd see bob's state changing, but sue never changes.// O expect sue's 5 objects to be the same object (identity), because this respects copy-on-write. Ie. we're not // making copies of elements that aren't changing.// The problem is that this means the same object appears many times in the state tree, which violates the listed pitfall.—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/immerjs/immer/issues/374?email_source=notifications&email_token=AAN4NBC4ZTEIP7J3ZVJAO6LPX6Y3DA5CNFSM4HP67CAKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODWSB2HI#issuecomment-497294621,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAN4NBDPOYMUVAVLT3FIPL3PX6Y3DANCNFSM4HP67CAA
.
Thanks for raising the issue!
I came here with the same question because the doc is unclear. It says
no object should appear twice in the tree
but doesn't say _why_ or _what will happen if there is an object which appears twice_.
I'm ok even if it will store them as two different instances. I just want to be sure that I can use immer in my project with the state like this:
{
contours: [contour1, contour2, ...],
selection: contour2
}
It is unclear for the exact reason it isn't specified :)
Immer is designed to be used on trees. In trees, _per definition_ an object never appears twice. So iff you don't give it a tree, but a graph instead we don't guarantee anything.
For example, changing store.selection.x = 3 might or might not show up in store.contours[2].x. It might or might not change it. And it could generate one or 2 json patches. It might produce one or 2 new objects. Etc etc. And for either behaviors one could give good arguments. Also, it might change per immer version. Because it is not a supported scenarios :). So if you do work with immer this way, do make sure you cover it with unit test (in both proxy and es5 mode), as the behavior in this case is not specified because we don't support it.
Most helpful comment
It is unclear for the exact reason it isn't specified :)
Immer is designed to be used on trees. In trees, _per definition_ an object never appears twice. So iff you don't give it a tree, but a graph instead we don't guarantee anything.
For example, changing
store.selection.x = 3might or might not show up instore.contours[2].x. It might or might not change it. And it could generate one or 2 json patches. It might produce one or 2 new objects. Etc etc. And for either behaviors one could give good arguments. Also, it might change per immer version. Because it is not a supported scenarios :). So if you do work with immer this way, do make sure you cover it with unit test (in both proxy and es5 mode), as the behavior in this case is not specified because we don't support it.