从渲染方法调用 React 中的 setState()

IT技术 reactjs redux
2021-04-19 20:12:24

我正在尝试使用 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();           
    }
2个回答

你可能想研究一下componentWillReceiveProps(nextProps)函数。根据官方文档:

componentWillReceiveProps()在安装的组件接收新的 props 之前调用。如果您需要更新状态以响应 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});
  }
}

每次 props 被发送到组件时,上面的代码片段都会运行。它首先检查resetMessagesprops是否为真。如果是,它将创建状态的临时副本company,更改idmessages属性值,然后company使用新值进行更新


我想强调您在代码中遇到的问题:

  1. 打电话setState()进去render()是不行的。

    每当您打电话时setState(),一般render()都会在之后运行。在内部这样做render()会导致该函数被一次又一次地调用......

  2. 直接改变状态和/或props。

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

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

@ user8125765,不客气。检查我在编辑中添加的评论。
2021-06-07 20:12:24
@Chris 您在第一句话中将方法名称拼错为“componentWillRecieveProps”(尽管在其他任何地方都是正确的)。
2021-06-19 20:12:24

componentWillReceiveProps现在已弃用(自 2018 年 6 月起)

您应该改用react 文档中提供的替代方案之一

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

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