繁体   English   中英

状态更新事件处理程序

[英]state updates on event handler

状态得到更新,而无需显式设置

我偶然碰到这个,这让我感到困惑。 据我了解,您的操作如下:

1创建当前状态的副本2修改副本3将修改后的副本分配给状态,从而对其进行更新。

这就是我的方法,并且效果很好。

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

但是奇怪和令人困惑的是,下面的代码也可以正常工作,但不必像上面那样在最后一行中显式分配它。只要我更新了不是它的引用的副本,它就会更新。

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.
    });

从您问题中的代码来看,您的州似乎具有类似于以下内容的结构:

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

其中items是对象数组。

当您这样做时:

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

您仅复制数组,但是newState数组中的对象仍与原始状态共享。 因此,您可以在不影响原始对象的情况下将新对象推送到数组中,但是这样做时:

newState[index][name]= value;

您要同时在原始状态和新状态下更改该对象。 运行下面的代码片段以查看演示。

 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> 

因此,在两个示例中,您的分配都在更改prevState,并且由于setState支持传递与先前状态合并的部分状态,因此当您返回空对象时,React会将其与突变的先前状态合并,然后重新渲染结果。

您正在使用传播语法复制状态。 传播语法仅执行浅表复制。 因此,当您更改新对象的嵌套属性时,它也会同时更改原始对象的嵌套属性。 这就是第二个代码起作用的原因。 您的变异状态与当前状态合并,即当前状态,您会看到变异的结果。 不要改变你的状态。

大多数时候,您应该使用诸如mapfilter方法来使新复制的对象发生变异,并且仅更改vale而不会改变原始状态。 因此,您可以将这些方法与扩展语法或Object.assign混合使用,但不要直接更改复制的方法。

由于我们不知道您的数据的确切形状,因此我只是在模仿以下代码。 如果您有索引,则可以使用此技术。

 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> 

但是,如果像在第二个示例中所做的那样更改此代码,则会看到它不起作用,因为我们不在此处更改原始状态。

 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