繁体   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