Reactjs 正确使用React getDerivedStateFromProps

Reactjs 正确使用React getDerivedStateFromProps,reactjs,Reactjs,在这个例子中 类计数器扩展React.Component{ 建造师(道具){ 超级(道具); this.state={count:0}; } 静态getDerivedStateFromProps(下一步,上一步){ console.log(“nextrops”,nextrops,“\nprevState”,prevState) if(nextrops.count!==prevState.count) 返回{count:nextrops.count}; 其他的 返回null; } 手动增量(e)

在这个例子中

类计数器扩展React.Component{
建造师(道具){
超级(道具);
this.state={count:0};
}
静态getDerivedStateFromProps(下一步,上一步){
console.log(“nextrops”,nextrops,“\nprevState”,prevState)
if(nextrops.count!==prevState.count)
返回{count:nextrops.count};
其他的
返回null;
}
手动增量(e){
this.setState({count:this.state.count+1})
}
处理过的文件(e){
this.setState({count:this.state.count-1})
}
render(){
返回
+
{this.state.count}
-
;
}
}
类Main扩展了React.Component{
建造师(道具){
超级(道具);
this.state={initialCount:1};
}
手变(e){
this.setState({initialCount:e.target.value})
}
render(){
返回

更改首字母: } } ReactDOM.render( , document.getElementById(“根”) );
预期: 单击+/-按钮和文本框更改必须是更新计数

目前: 主组件将initialCount存储在自己的状态中,并将初始计数传递给子计数器组件

若从textbox触发handleChange并更新initialCount,则子计数器组件也会正确更新,因为getDerivedStateFromProps静态方法提供了这一点

但通过handleIncrease和HandleDecrese方法更新局部状态来改变计数器组件中的计数值是不可能的

问题是getDerivedStateFromProps这次重新触发并重置计数值。但我并没有预料到这一点,因为计数器组件本地状态更新父主组件并没有更新。不安全组件将以这种方式接收道具

总结:我的getDerivedStateFromProps使用不正确,或者我的场景有其他解决方案


此版本适用于componentWillReceiveProps

我不确定我是否理解正确,但如果您想将该道具用作初始值的“种子”,以便在构造函数中执行此操作,并且您甚至不需要
getDerivedStateFromProps
。实际上,您不需要复制状态:

class Counter extends React.Component {
  render() {
    return <div>
      <button onClick={this.props.handleIncrease}>+</button>
      {this.props.count}
      <button onClick={this.props.handleDecrease}>-</button>
    </div>;
  }
}

class Main extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 1 };
  }
  handleIncrease() {
    this.setState(prevState => ({count: prevState.count + 1}))  
  }
  handleDecrease() {
    this.setState(prevState => ({count: prevState.count - 1}))  
  }
  render() {
    return (
     <div>
      <Counter count={this.state.count} />
      <hr/>
      Change initial: 
      <input 
        type="number" 
        handleIncrease={this.handleIncrease.bind(this)} 
        handleDecrease={this.handleDecrease.bind(this)} 
        count={this.state.count} 
      />
     </div>
    )
  }
}
类计数器扩展React.Component{
render(){
返回
+
{this.props.count}
-
;
}
}
类Main扩展了React.Component{
建造师(道具){
超级(道具);
this.state={count:1};
}
handleIncrease(){
this.setState(prevState=>({count:prevState.count+1}))
}
HandleDecrese(){
this.setState(prevState=>({count:prevState.count-1}))
}
render(){
返回(

更改首字母: ) } }
像您这样尝试将状态“同步”到道具,极易出错,并导致应用程序出现错误

事实上,甚至你的电脑也有一个bug。
如果更频繁地重新渲染父组件,将丢失用户输入

这是一本书。 增加计数器,然后单击“演示错误”,它将吹走计数器。但是这个按钮的
setState
应该是完全不相关的

这说明了为什么尝试将状态同步到道具是个坏主意,应该避免

相反,请尝试以下方法之一:

  • 您可以使组件完全由父道具“控制”,并删除本地状态

  • 或者,您可以使组件完全“不受控制”,并在必要时通过给子组件一个不同的
    键来从父组件重置子组件状态


  • 中描述了这两种方法。这篇博文包含了详细的示例和演示,因此我强烈建议您查看。

    谢谢Tomasz。你的建议是另一种解决方案,但我不能在现实世界中使用它。组件必须使用自己的事件处理程序更新自己的状态。
    class Counter extends React.Component {
      render() {
        return <div>
          <button onClick={this.props.handleIncrease}>+</button>
          {this.props.count}
          <button onClick={this.props.handleDecrease}>-</button>
        </div>;
      }
    }
    
    class Main extends React.Component {
      constructor(props) {
        super(props);
        this.state = { count: 1 };
      }
      handleIncrease() {
        this.setState(prevState => ({count: prevState.count + 1}))  
      }
      handleDecrease() {
        this.setState(prevState => ({count: prevState.count - 1}))  
      }
      render() {
        return (
         <div>
          <Counter count={this.state.count} />
          <hr/>
          Change initial: 
          <input 
            type="number" 
            handleIncrease={this.handleIncrease.bind(this)} 
            handleDecrease={this.handleDecrease.bind(this)} 
            count={this.state.count} 
          />
         </div>
        )
      }
    }