在render方法中调用React中的setState()

use*_*765 6 reactjs redux

我试图使用setState()方法重置容器中的React状态变量(默认值).但是得到以下错误

 Warning: setState(...): Cannot update during an existing state transition 
(such as within `render` or another component's constructor). Render methods 
 should be a pure function of props and state; constructor side-effects are an anti-pattern, 
 but can be moved to `componentWillMount`.
Run Code Online (Sandbox Code Playgroud)

最后:超出最大调用堆栈大小.

我的代码如下:

resetMsg=()=>  {  
const company = this.state.company;
company.id = 0;
company.messages = [];    
this.setState({company: company});       
}
Run Code Online (Sandbox Code Playgroud)

当Redux状态的变量为true时,我调用resetMsg().

我调用resetMsg的代码(resetMessages的值最初为false,我需要重置React-state,当它为true时):

    render() {
    if(this.props.resetMessages){           
        this.resetMsg();           
    }
Run Code Online (Sandbox Code Playgroud)

Chr*_*ris 15

您可能想要查看componentWillReceiveProps(nextProps)功能.根据官方文件:

componentWillReceiveProps()在安装的组件接收新道具之前调用.如果您需要更新状态以响应prop更改(例如,重置它),您可以比较this.props和nextProps并使用此方法中的this.setState()执行状态转换.

这是您想要进行重置的地方.所以类似于:

componentWillReceiveProps(nextProps) {
  if(nextProps.resetMessages) {
    const company = Object.assign({}, this.state.company);
    company.id = 0;
    company.messages = [];    
    this.setState({company: company});
  }
}
Run Code Online (Sandbox Code Playgroud)

每次将道具发送到组件时,上面的代码段都会运行.它首先检查resetMessages支柱是否真实.如果是,它将创建状态的临时副本company,更改idmessages属性值,然后company使用新的更新.


我想强调您对代码的问题:

  1. setState()里面打电话render()是禁忌.

    无论什么时候你打电话setState(),render()都会在之后进行.在内部执行此操作render()将导致再次调用该函数,并再次,...

  2. 直接改变状态和/或道具.

    此行const company = this.state.company;不会创建状态变量的副本.它只存储对它的引用.所以一旦你这样做,然后company.id = ...你基本上做了this.state.company.id = ...,这是React中的反模式.我们只会改变状态setState().

    要创建副本,请使用Object.assign({}, this.state.yourObject)对象和this.state.yourArray.slice()数组.


Lar*_*zan 6

componentWillReceiveProps弃用(自18年6月以来)

您应该使用react docs中提供的替代方法之一。

在您的情况下,我猜想使用使用getDerivedStateFromProps的“不那么推荐”替代版本1是合理的,因为您只是在重新计算状态vars:

getDerivedStateFromProps(props, state) {
  if(props.resetMessages) {
    const company = Object.assign({}, state.company);
    company.id = 0;
    company.messages = [];    
    return {
      company: company
   }
}
Run Code Online (Sandbox Code Playgroud)