As you mentioned, you can use Object.assign
in place of spread:
{...state, x: 1}
should give you the same result as
Object.assign({}, state, {x: 1})
Note the empty object as the first parameter of Object.assign
. What this is doing is copying the values from state
into a new empty object, then copying the values from {first: 1}
into the new object.
For example:
var a = { x: 1, y: 2}
var b = {...a, y: 3 }
console.log(a); // { x: 1, y: 2 }
console.log(b); // { x: 1, y: 3 }
is equivalent to
var c = { x: 1, y: 2 }
var d = Object.assign({}, a, { y: 3 });
console.log(c); // { x: 1, y: 2 }
console.log(d); // { x: 1, y: 3 }
The important part is that both a
and c
are unchanged. b
and d
have a new value for y
.
For nested objects, you repeat this process:
function updateVeryNestedField(state, action) {
return Object.assign({}, state, {
first : Object.assign({}, state.first, {
second : Object.assign({}, state.first.second, {
[action.someId] : Object.assign({},
state.first.second[action.someId],
{ fourth : action.someValue }
)
})
})
});
}
var oldState = { first: { second: { 'anId': { fourth: 3 } } } };
var newState = updateVeryNestedField(oldState, { someId: 'anId', someValue: 5 });
console.log(oldState.first.second.anId.fourth); // 3
console.log(newState.first.second.anId.fourth); // 5
However, for full ES2015 support you also won't be able to use computed keys. So instead you'd have build some of the object before the return statement. For example:
function updateVeryNestedField(state, action) {
// Create a temporary object to avoid use of computed keys
var updatedSecond = Object.assign({}, state.first.second);
updatedSecond[action.someId] = Object.assign({}, state.first.second[action.someId], {
fourth: action.someValue
});
return Object.assign({}, state, {
first : Object.assign({}, state.first, { second : updatedSecond })
});
}
var oldState = { first: { second: { 'anId': { fourth: 3 } } } };
var newState = updateVeryNestedField(oldState, { someId: 'anId', someValue: 5 });
console.log(oldState.first.second.anId.fourth); // 3
console.log(newState.first.second.anId.fourth); // 5