亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

React是否保持狀態更新的順序?

React是否保持狀態更新的順序?

喵喔喔 2019-11-05 14:22:10
我知道React可以異步執行批處理狀態更新以優化性能。因此,在調用之后,您將永遠無法相信要更新的狀態setState。但是你可以信任的反應更新相同的順序狀態setState被稱為對相同的組件?不同的組件?考慮在以下示例中單擊按鈕:1.在以下情況下,是否有可能a為假而b為真:class Container extends React.Component {  constructor(props) {    super(props);    this.state = { a: false, b: false };  }  render() {    return <Button onClick={this.handleClick}/>  }  handleClick = () => {    this.setState({ a: true });    this.setState({ b: true });  }}2.在以下情況下,是否有可能a為假而b為真:class SuperContainer extends React.Component {  constructor(props) {    super(props);    this.state = { a: false };  }  render() {    return <Container setParentState={this.setState.bind(this)}/>  }}class Container extends React.Component {  constructor(props) {    super(props);    this.state = { b: false };  }  render() {    return <Button onClick={this.handleClick}/>  }  handleClick = () => {    this.props.setParentState({ a: true });    this.setState({ b: true });  }}請記住,這些是我用例的極端簡化。我意識到我可以以不同的方式進行操作,例如,在示例1中同時更新兩個狀態參數,以及在示例2中的第一個狀態更新的回調中執行第二個狀態更新。但是,這不是我的問題,我只對React是否有明確定義的方式來執行這些狀態更新感興趣,僅此而已。非常感謝文檔支持的任何答案。
查看完整描述

3 回答

?
慕少森

TA貢獻2019條經驗 獲得超9個贊

我在做React。


TLDR:


但是你可以相信React可以按照要求setState的順序更新狀態嗎


相同的組件?

是。


不同的組件?

是。


該訂單的更新總是尊重。是否在它們之間看到中間狀態取決于您是否在批處理中。


當前(React 16和更早版本),默認情況下僅批處理React事件處理程序中的更新。有一個不穩定的API可以在極少數情況下在需要時強制在事件處理程序之外進行批處理。


在未來的版本中(可能是React 17及更高版本),React默認會批處理所有更新,因此您無需考慮這一點。與往常一樣,我們將在React博客和發行說明中宣布對此所做的任何更改。


理解這一點的關鍵是,無論setState()您在React事件處理程序中執行了多少個組件中的多少次調用,它們都將在事件結束時僅產生一次重新渲染。這對于大型應用程序性能良好至關重要的,因為如果Child與Parent每個呼叫setState()處理click事件的時候,你不想重新渲染Child兩次。


在您的兩個示例中,setState()調用都在React事件處理程序中進行。因此,它們總是在事件結束時一起刷新(并且您看不到中間狀態)。


更新總是按照發生的順序進行淺層合并。因此,如果第一個更新為{a: 10},第二個為{b: 20},第三個為{a: 30},則渲染狀態將為{a: 30, b: 20}。對相同狀態鍵的更新(例如,a在我的示例中)總是“獲勝”。


this.state當我們在批處理結束時重新呈現UI時,將更新該對象。因此,如果您需要基于先前的狀態(例如增加計數器)來更新狀態,則應使用setState(fn)為您提供先前狀態的功能版本,而不是從中讀取this.state。如果您對此原因感到好奇,我會在此評論中對其進行深入解釋。


在你的榜樣,我們也不會看到“中間狀態”,因為我們是一個作出反應事件處理中在啟用配料(因為響應“知道”什么時候我們退出該事件)。


但是,在React 16和早期版本中,默認情況下,在React事件處理程序之外都沒有批處理。因此,如果在您的示例中,我們使用AJAX響應處理程序而不是handleClick,則每個處理程序setState()都會在發生時立即進行處理。在這種情況下,是的,您會看到一個中間狀態:


promise.then(() => {

  // We're not in an event handler, so these are flushed separately.

  this.setState({a: true}); // Re-renders with {a: true, b: false }

  this.setState({b: true}); // Re-renders with {a: true, b: true }

  this.props.setParentState(); // Re-renders the parent

});

我們意識到,根據您是否在事件處理程序中,行為會有所不同,這很不方便。這將在以后的React版本中更改,該版本默認情況下將批處理所有更新(并提供選擇加入的API以同步刷新更改)。在我們切換默認行為(可能在React 17中)之前,有一個可用于強制批處理的API:


promise.then(() => {

  // Forces batching

  ReactDOM.unstable_batchedUpdates(() => {

    this.setState({a: true}); // Doesn't re-render yet

    this.setState({b: true}); // Doesn't re-render yet

    this.props.setParentState(); // Doesn't re-render yet

  });

  // When we exit unstable_batchedUpdates, re-renders once

});

內部React事件處理程序都被包裝,unstable_batchedUpdates這就是為什么默認情況下對它們進行批處理的原因。請注意,將更新打包unstable_batchedUpdates兩次是無效的。當我們退出最外部的unstable_batchedUpdates調用時,將刷新更新。


該API是“不穩定的”,即默認情況下啟用批處理后我們將其刪除。但是,我們不會在次要版本中將其刪除,因此在某些情況下,如果需要在React事件處理程序之外強制執行批處理,則可以放心地使用它直到React 17。


綜上所述,這是一個令人困惑的話題,因為默認情況下,React僅在事件處理程序中進行批處理。這將在將來的版本中更改,并且行為將變得更加簡單。但是解決方案不是少批處理,而是默認情況下多批處理。那就是我們要做的。


查看完整回答
反對 回復 2019-11-05
?
富國滬深

TA貢獻1790條經驗 獲得超9個贊

這實際上是一個非常有趣的問題,但答案應該不會太復雜。在媒體上有一篇很棒的文章有答案。


1)如果這樣做


this.setState({ a: true });

this.setState({ b: true });

我不認為會出現的情況下a會true和b會false因為配料。


但是,如果b取決于,a則確實可能存在無法獲得預期狀態的情況。


// assuming this.state = { value: 0 };

this.setState({ value: this.state.value + 1});

this.setState({ value: this.state.value + 1});

this.setState({ value: this.state.value + 1});

處理完所有上述調用后,this.state.value將為1,而不是您期望的3。


這是在文章中提到的: setState accepts a function as its parameter


// assuming this.state = { value: 0 };

this.setState((state) => ({ value: state.value + 1}));

this.setState((state) => ({ value: state.value + 1}));

this.setState((state) => ({ value: state.value + 1}));

這會給我們 this.state.value === 3


查看完整回答
反對 回復 2019-11-05
  • 3 回答
  • 0 關注
  • 721 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號