Right way to clone objects / arrays during setState in React
Answer a question
I start with:
constructor() {
super();
this.state = {
lists: ['Dogs','Cats'],
items: {Dogs: [{name: "Snoopy"}, {name: "Lola"}, {name: "Sprinkles"}],
Cats: [{name: "Felidae"}, {name: "Garfiled"}, {name: "Cat in the Hat"}] }
};
}
then I have my addItem function:
handleAddItem(s) {
var key = Object.keys(s)[0];
var value = s[key];
var allItems = {...this.state.items};
allItems[key].push({name: value});
this.setState({items: allItems});
}
elsewhere I define s as:
var s={};
s[this.props.idName] = this.refs.id.value;
This works but I'm wondering if this is the right way to add an element into one of the keys in items. AllItems is really pointing to this.state.items and I thought it should be a deep copy but I'm not sure how to do that.
It seems like items is an object that holds key/value pairs where the value is an array. Is that correct? Where can I go to learn how to manipulate a structure like that?
Answers
I personally rely on this deep copy strategy. JSON.parse(JSON.stringify(object)) rather than spread operator because it got me into weird bugs while dealing with nested objects or multi dimensional arrays.
spread operator does not do a deep copy if I am correct and will lead to state mutations with NESTED objects in React.
Please run through the code to get a better understanding of what is happening between the two. Imagine that is the state variable that you mutate using spread operator.
const obj = {Dogs: [{name: "Snoopy"}, {name: "Lola"}, {name: "Sprinkles"}], Cats: [{name: "Felidae"}, {name: "Garfiled"}, {name: "Cat in the Hat"}] };
const newObj = {...obj};
console.log("BEFORE SPREAD COPY MUTATION")
console.log("NEW OBJ: " + newObj.Dogs[0].name); //Snoopy
console.log("OLD OBJ: " + obj.Dogs[0].name); //Snoopy
newObj.Dogs[0].name = "CLONED Snoopy";
console.log("AFTER SPREAD COPY MUTATION")
console.log("NEW OBJ: " + newObj.Dogs[0].name); // CLONED Snoopy
console.log("OLD OBJ: " + obj.Dogs[0].name); // CLONED Snoopy
// Even after using the spread operator the changed on the cloned object are affected to the old object. This happens always in cases of nested objects.
// My personal reliable deep copy
console.log("*********DEEP COPY***********");
console.log("BEFORE DEEP COPY MUTATION")
deepCopyObj = JSON.parse(JSON.stringify(obj));
console.log("NEW OBJ: " + newObj.Dogs[0].name); //CLONED Snoopy
console.log("OLD OBJ: " + obj.Dogs[0].name); // CLONED Snoopy
console.log("DEEP OBJ: " + deepCopyObj.Dogs[0].name); //CLONED Snoopy
deepCopyObj.Dogs[0].name = "DEEP CLONED Snoopy";
console.log("AFTER DEEP COPY MUTATION")
console.log("NEW OBJ: " + newObj.Dogs[0].name); // CLONED Snoopy
console.log("OLD OBJ: " + obj.Dogs[0].name); // CLONED Snoopy
console.log("DEEP OBJ: " + deepCopyObj.Dogs[0].name); // DEEP CLONED Snoopy
Now, if you wanted to do a deep copy on your object change the handler to this
handleAddItem(s) {
var key = Object.keys(s)[0];
var value = s[key];
var allItems = JSON.parse(JSON.stringify(this.state.items));
allItems[key].push({name: value});
this.setState({items: allItems});
}
更多推荐
所有评论(0)