I am trying to create a deep copy map method for my Redux project that will work with objects rather than arrays. I read that in Redux each state should not change anything in the previous states.
export const mapCopy = (object, callback) => {
return Object.keys(object).reduce(function (output, key) {
output[key] = callback.call(this, {...object[key]});
return output;
},
{});
}
It works:
return mapCopy(state, e => {
if (e.id === action.id) {
e.title = 'new item';
}
return e;
})
However it does not deep copy inner items so I need to tweak it to:
export const mapCopy = (object, callback) => {
return Object.keys(object).reduce(function (output, key) {
let newObject = {...object[key]};
newObject.style = {...newObject.style};
newObject.data = {...newObject.data};
output[key] = callback.call(this, newObject);
return output;
}, {});
}
This is less elegant as it requires to know which objects are passed. Is there a way in ES6 to use the spread syntax to deep copy an object?
No such functionality is built-in to ES6. I think you have a couple of options depending on what you want to do.
If you really want to deep copy:
cloneDeep
method.However, I think, if you're willing to change a couple things, you can save yourself some work. I'm assuming you control all call sites to your function.
Specify that all callbacks passed to mapCopy
must return new objects instead of mutating the existing object. For example:
mapCopy(state, e => {
if (e.id === action.id) {
return Object.assign({}, e, {
title: 'new item'
});
} else {
return e;
}
});
This makes use of Object.assign
to create a new object, sets properties of e
on that new object, then sets a new title on that new object. This means you never mutate existing objects and only create new ones when necessary.
mapCopy
can be really simple now:
export const mapCopy = (object, callback) => {
return Object.keys(object).reduce(function (output, key) {
output[key] = callback.call(this, object[key]);
return output;
}, {});
}
Essentially, mapCopy
is trusting its callers to do the right thing. This is why I said this assumes you control all call sites.