簡體   English   中英

React組件的props如何異步更新?

[英]How is React component's props updated asynchronously?

深入研究之后,我以為我理解了組件的props不能由組件本身更新,盡管可以由父組件更改。

但是我在react docs中找到了這一部分:

React可以將多個setState()調用批處理到單個更新中以提高性能。 由於this.props和this.state可以異步更新,因此您不應依賴於它們的值來計算下一個狀態。

因此,我試圖以我所理解的來解釋該摘錄所說的內容。 如果道具已更新,則更新必須來自父組件。 如果更新來自父組件,為什么它可能是異步的?

請在此處檢查zloctb給出的答案

// assuming this.state.count === 0
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
this.setState({count: this.state.count + 1});
// this.state.count === 1, not 3

Solution
this.setState((prevState, props) => ({
  count: prevState.count + props.increment
}));

如果道具已更新,則更新必須來自父組件。

那是對的。

如果更新來自父組件,為什么它可能是異步的?

您可以將帶有道具的父母的setState()傳遞給孩子,並在孩子的代碼中的某個地方調用它。 而且它仍然可能是異步的。 我想出了以下示例:

class Container extends React.Component {
  state = { containerState: 0 };
  render() {
    return (
      <Component
        containerState={this.state.containerState}
        setContainerState={this.setState.bind(this)}
      />
    );
  }
}

然后,在子Component ,您具有如下代碼:

this.props.setContainerState({
  containerState: this.props.containerState + 1
});

// You want to use updated this.props.containerState here, but you can't,
// because parent's setState() MAY BE deferred
this.props.setState({ componentStateUpdatedWithObject: this.props.containerState });

// Now if you use the function instead, you can expect to get updated props
// as a second argument
this.props.setState((state, props) => ({ 
  componentStateUpdatedWithFunction: props.containerState 
}));

請參閱完整的代碼作為我的示例:

 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <title>Document</title> </head> <body> <div id="root"></div> </body> <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin ></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin ></script> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script type="text/babel"> class Container extends React.Component { state = { containerState: 0 }; render() { return ( <Component containerState={this.state.containerState} setContainerState={this.setState.bind(this)} /> ); } } class Component extends React.Component { state = { componentStateUpdatedWithObject: [0, this.props.containerState], componentStateUpdatedWithFunction: [0, this.props.containerState] }; log = title => { console.log(title); console.log("- containerState", this.props.containerState); console.log( "- componentStateUpdatedWithObject", this.state.componentStateUpdatedWithObject ); console.log( "- componentStateUpdatedWithFunction", this.state.componentStateUpdatedWithFunction ); console.log("=========="); }; update = () => { this.log("before update"); this.props.setContainerState({ containerState: this.props.containerState + 1 }); this.log("after setContainerState"); this.setState({ componentStateUpdatedWithObject: [ this.state.componentStateUpdatedWithObject[0] + 1, this.props.containerState ] }); this.log("after setState with object"); this.setState((state, props) => ({ componentStateUpdatedWithFunction: [ state.componentStateUpdatedWithFunction[0] + 1, props.containerState ] })); this.log("after setState with function"); }; componentDidMount() { // setInterval(this.update, 2000); } render() { this.log("on render"); console.log("---------------------------------------------"); return ( <div> <div>containerState: {this.props.containerState}</div> <div> componentStateUpdatedWithObject:{" "} {this.state.componentStateUpdatedWithObject.join(", ")} </div> <div> componentStateUpdatedWithFunction:{" "} {this.state.componentStateUpdatedWithFunction.join(", ")} </div> <button onClick={this.update}>UPDATE</button> </div> ); } } ReactDOM.render(<Container />, document.getElementById("root")); </script> </html> 

注意:並非所有setState()調用都是異步的。 在我的例子,如果你取消注釋setInterval(this.update, 2000)componentDidMount ,你不會得到相同的行為。 這樣setState()調用是同步的。

請參閱此鏈接以了解發生這種情況的原因: setState()調用何時以及為什么批量處理?

簡而言之,這是因為

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM