简体   繁体   English

状态更新事件处理程序

[英]state updates on event handler

State gets updated without having to set it explicitly 状态得到更新,而无需显式设置

I ran to this by accident and it confused me. 我偶然碰到这个,这让我感到困惑。 As far as I know you do it as following: 据我了解,您的操作如下:

1-create a copy of the current state 2-modify the copy 3-assign the modified copy to state hence updating it. 1创建当前状态的副本2修改副本3将修改后的副本分配给状态,从而对其进行更新。

This is how I do it and it works fine. 这就是我的方法,并且效果很好。

handleChange(index, event) {
    const {name, value} = event.target;
    this.setState((prevState) => {
        const newState = [...prevState.items];
        newState[index][name]= value;
        return{items: newState};
    });

But the strange and confusing thing is that the below code also works as well but without having to explicitly assign it in the last line as the above.it is updating as soon as I update the copy which is Not a reference of it. 但是奇怪和令人困惑的是,下面的代码也可以正常工作,但不必像上面那样在最后一行中显式分配它。只要我更新了不是它的引用的副本,它就会更新。

handleChange(index, event) {
    const {name, value} = event.target;
    this.setState((prevState) => {
        const newState = [...prevState.items];
        newState[index][name]= value;

        return{}; //it works as long as I have the brackets.
    });

From the code in your question, it looks like your state has a structure similar to the following: 从您问题中的代码来看,您的州似乎具有类似于以下内容的结构:

state = { items: [{name1: 'index0Value1', name2: 'index0Value2'}, {name1: 'index1Value1', name2: 'index1Value2'}] }; 状态= {项目:[{name1:'index0Value1',name2:'index0Value2'},{name1:'index1Value1',name2:'index1Value2'}]};

where items is an array of objects. 其中items是对象数组。

When you do: 当您这样做时:

const newState = [...prevState.items];

you are copying the array only, but the objects within newState 's array are still shared with the original state. 您仅复制数组,但是newState数组中的对象仍与原始状态共享。 So you could push a new object into your array without affecting the original, but when you do: 因此,您可以在不影响原始对象的情况下将新对象推送到数组中,但是这样做时:

newState[index][name]= value;

you are changing that object in both the original state and your new state. 您要同时在原始状态和新状态下更改该对象。 Run the snippet below to see this demonstrated. 运行下面的代码片段以查看演示。

 const prevState = { items: [{name1: 'index0Value1', name2: 'index0Value2'}, {name1: 'index1Value1', name2: 'index1Value2'}] }; document.getElementById('origbefore').innerHTML = 'prevState before='+JSON.stringify(prevState); const newItems = [...prevState.items]; newItems[0]['name1']='tryingToOnlyChangeNewState'; const newState = { items: newItems }; document.getElementById('origafter').innerHTML = 'prevState after='+JSON.stringify(prevState); document.getElementById('new').innerHTML = 'newState='+JSON.stringify(newState); 
 <div id="origbefore"></div> <div id="origafter"></div> <div id="new"></div> 

So in both examples, your assignment is changing prevState, and since setState supports passing in a partial state which gets merged in with the previous state, when you return an empty object, React merges that with the mutated previous state and then re-renders with the result. 因此,在两个示例中,您的分配都在更改prevState,并且由于setState支持传递与先前状态合并的部分状态,因此当您返回空对象时,React会将其与突变的先前状态合并,然后重新渲染结果。

You are using spread syntax to copy your state. 您正在使用传播语法复制状态。 Spread syntax only does shallow copies. 传播语法仅执行浅表复制。 So when you change a nested property of your new object it also mutates the original one. 因此,当您更改新对象的嵌套属性时,它也会同时更改原始对象的嵌套属性。 This is why your second code works. 这就是第二个代码起作用的原因。 Your mutated state merged with the current state, which is itself, and you see the mutated result. 您的变异状态与当前状态合并,即当前状态,您会看到变异的结果。 Do not mutate your state. 不要改变你的状态。

Most of the time you should use method likes map , filter to mutate the newly copied object and just change the vale without mutating the original state. 大多数时候,您应该使用诸如mapfilter方法来使新复制的对象发生变异,并且仅更改vale而不会改变原始状态。 So, you can mix those methods with spread syntax or Object.assign but do not directly mutate the copied one. 因此,您可以将这些方法与扩展语法或Object.assign混合使用,但不要直接更改复制的方法。

Since we don't know the exact shape of your data I'm just mimicking something like the code below. 由于我们不知道您的数据的确切形状,因此我只是在模仿以下代码。 You can use this technique if you have an index. 如果您有索引,则可以使用此技术。

 class App extends React.Component { state = { items: [{ foo: "a foo" }, { bar: "a bar" }, { baz: "a baz" }], }; handleChange(index, event) { const { name, value } = event.target; const { items } = this.state; const newItems = Object.assign([], items, { [index]: { ...items[index], [name]: value }, }); this.setState({ items: newItems }); } render() { return ( <div> {this.state.items.map((item, index) => ( <input name={Object.keys(item)} key={Object.keys(item)} index={index} onChange={(event) => this.handleChange(index, event)} /> ))} <div> {this.state.items.map((item) => ( <p key={Object.values(item)}>{Object.values(item)}</p> ))} </div> </div> ); } } ReactDOM.render( <App />, document.getElementById("root") ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div> 

But, if you change this code as you do in your second example, you will see that it won't work since we are not mutating the original state here. 但是,如果像在第二个示例中所做的那样更改此代码,则会看到它不起作用,因为我们不在此处更改原始状态。

 class App extends React.Component { state = { items: [{ foo: "a foo" }, { bar: "a bar" }, { baz: "a baz" }], }; handleChange(index, event) { const { name, value } = event.target; const { items } = this.state; const newItems = Object.assign([], items, { [index]: { ...items[index], [name]: value }, }); // this.setState({ items: newItems }); this.setState({}); } render() { return ( <div> {this.state.items.map((item, index) => ( <input name={Object.keys(item)} key={Object.keys(item)} index={index} onChange={(event) => this.handleChange(index, event)} /> ))} <div> {this.state.items.map((item) => ( <p key={Object.values(item)}>{Object.values(item)}</p> ))} </div> </div> ); } } ReactDOM.render( <App />, document.getElementById("root") ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM