问题
Parent component is a header
Child component is a form which is used to change values appearing in the header after a save which fires a redux action.
I set the child state with
constructor(props) {
super(props);
this.state = {
object: { ...props.object },
hidden: props.hidden,
};
}
The form is used to render the state.object and modify the state.object. When I modify state.object, the props from the parent component change as well.
handleObjectChange = (event, key, subkey) => {
console.log('props', this.props.object.params);
console.log('state', this.state.object.params);
event.preventDefault();
const value = this.handlePeriod(event.target.value);
this.setState((prevState) => {
const object = { ...prevState.object };
object[key][subkey] = value;
return { object };
});
}
Console output:
newvalueijusttyped
newvalueijusttyped
This behavior actually goes all the way up to modifying the redux store without ever having dispatched an action.
Would appreciate a solution for this issue
Update:
Changing the constructor to this solved the issue
constructor(props) {
super(props);
this.state = {
object: JSON.parse(JSON.stringify(props.object)),
hidden: props.hidden,
};
}
Why doesn't the object spread operator achieve what I'm trying to accomplish?
回答1:
Javascript object are assigned by reference so when you do
constructor(props) {
super(props);
this.state = {
object: props.object,
hidden: props.hidden,
};
}
state is referencing the redux state object(if it is a redux state). So now when you use
this.setState((prevState) => {
const object = { ...prevState.object };
object[key][subkey] = value;
return { object };
});
Although you would assume that you have cloned the object value into a new object. However Spread syntax does only a one level copy of the object.
From the Spread Syntax MDN docs:
Note: Spread syntax effectively goes one level deep while copying an array. Therefore, it may be unsuitable for copying multidimensional arrays as the following example shows (it's the same with Object.assign() and spread syntax).
var a = [1, [2], [3]]; var b = [...a]; b.shift().shift(); // 1 // Now array a is affected as well: [[], [2], [3]]
So effectively
object[key][subkey] = value;
changes the value directly in redux store.
Solution is create a nested copy like
const object = { ...prevState.object,
[key]: {
...prevState[key],
[subkey]: { ...prevState[key][subkey]}
}
};
object[key][subkey] = value;
回答2:
Objects in javascript are 'passed by reference'.
If you are passing the parent's props as state to the children, then when you change the state, you are in effect mutating the very same object that was passed to it.
Use Object.assign() to create a clone of the data before you make it part of the child's state.
来源:https://stackoverflow.com/questions/45317976/changing-a-child-components-state-changes-the-parent-components-props