Unexpected behavior of Object.assign() in Immer in Redux

Viewed 1629

I'm using redux-starter-kit (which includes Immer library for mutable updates) and for some reason this reducer doesn't work:

reInitializeState(state, action) {
        state = Object.assign({}, initialState);
        state.someProperty = true; // this does not get set
    },

But this one does:

reInitializeState(state, action) {
        Object.assign(state, initialState);
        state.someProperty = true; // this does
    },

I would expect them to do the same thing. What is going on here?

3 Answers

With Immer you mutate objects in-place for creating the next immutable copy. In the first example, because state comes in as a param, doing:

state = Object.assign({}, initialState);

reassigns state to a new object, so setting someProperty on that new object doesn't cause any changes -- you have to mutate on the param itself.

In the second example, you don't reassign state to something else, so calling state.someProperty and modifying it modifies the original state object.

Reassigning a variable, by itself, will almost never have any effect elsewhere. If you pass a variable as a parameter, then reassign that variable, and the function ends, nothing outside of the function will see any change. Similarly:

let someVar = 'foo';
function reassign(str) {
  str = 'bar';
}
reassign(someVar);
console.log(someVar);

Reassigning inside the function above doesn't do anything, because the reassignment does not change what the outer binding of someVar points to.

Your second snippet:

reInitializeState(state, action) {
    Object.assign(state, initialState);
    state.someProperty = true; // this does
},

Here, you're mutating the original state object that was passed as a parameter, so the change is seen outside the function. In the other snippet, you're mutating an entirely new object, an object which cannot be seen elsewhere in the script, and proceeds to get garbage collected.

What you're doing here:

state = Object.assign({}, initialState);

Is copying initialState into a new object, and discarding the contents of state. You should be assigning to state not to {}, and assigning the result to state.

state = Object.assign(state, initialState);
Related