簡體   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