I joined a React project with no immutability library or middleware, but it's too far-gone to make that change now, especially considering it's never actually caused any issues, until this one example today.
In cases where I need a bit more control than simple lodash.cloneDeep, I typically use the {...spread}
method to clone an object, and remembering that this only creates a shallow clone, propagate the same method down the tree of modified nested properties (which thankfully never goes very deep), eg:
// there are a dozen variations on how you might do this...
const modifiedObj = {
...originalObj,
list: [
...originalObj.list,
newItem,
]
};
In this case though, I'd missed an ancestor somewhere, causing the original object to be mutated, and scanning up and down this 30-line function, I couldn't find where the mutation was happening.
A brainwave called out from deep inside: "Object.freeze
!". No, it wasn't a suggestion to freeze this.props.myProperty
to prevent the mutation (I just assume that's a very bad idea), but I could use it as a temporary debugging tool.
Remembering that Object.freeze
also only works shallowly, I pulled out this deepFreeze()
function from the Mozilla docs:
// NB: you may need to apply "use strict" based on your project set-up
function deepFreeze(object) {
// Retrieve the property names defined on object
var propNames = Object.getOwnPropertyNames(object);
// Freeze properties before freezing self
for (let name of propNames) {
let value = object[name];
object[name] = value && typeof value === "object" ?
deepFreeze(value) : value;
}
return Object.freeze(object);
}
Now apply this function to the source of any cloned object you want to debug before the mutation occurs, and the browser console will conveniently throw an error at the exact line where the mutation was being inadvertently attempted:
const onlyShallowCloned = { ...this.props.myProp};
deepFreeze(this.props.myProp);
someDeepManipulation(onlyShallowCloned);
And easy as that, the now-obvious offending line slaps you in the face as you kick yourself: ahh it was there all along!.
Top comments (1)
You can also use setters to figure out where a mutation on a specific property is coming from:
This way you don't need to put
use strict
everywhere to find the culprit.