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

时间:2018-01-12 12:25:21

标签: 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`.

最后:超出了最大调用堆栈大小。

我的代码如下:

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

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

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

    render() {
    if(this.props.resetMessages){           
        this.resetMsg();           
    }

3 个答案:

答案 0 :(得分:11)

您可能需要查看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});
  }
}

每次将道具发送到组件时,上面的代码段都会运行。它首先检查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()

答案 1 :(得分:5)

componentWillReceiveProps现在(自18年6月以来)已被弃用

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

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

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

答案 2 :(得分:0)

使用componentWillReceiveProps检查道具

export class SomeClass {
  resetMsg = () => {  
    let newCompany = {} // don't reuse state.company, create new object!
    newCompany = 0;
    newCompany.messages = [];    
    this.setState({company: newCompany});       
  }

  componentWillReceiveProps = (nextProps) => {
    if (nextProps.resetMessages !== this.props.resetMessages) { // check if props changed
      if (nextProps.resetMessages === true) { // check if prop has correct value
        this.resetMsg()
      }
    }
  }

  render () {
    return () // Your super cool app code
  }
}