React组件触发Maximum update depth exceeded报错,求排查解决
你的代码
export class ABC extends React.Component { constructor(props) { super(props); this.state = { abc: null }; } renderOptions() { this.setState({ abc: abcArray.length !== 0 }); return; } renderRadio() { return ( <Field id="abc" name="abc" values={this.renderOptions()} /> ); } render() { return ( <div> {this.renderRadio()} </div> ); } } export default connect(mapStateToProps)(ABC);
报错信息
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
错误原因
你在renderOptions方法里调用了setState,而这个方法是在组件render阶段被执行的(作为Field组件的values属性值被调用)。React中,setState会触发组件重新渲染,重新渲染时又会执行render,再次调用renderRadio,进而再次调用renderOptions执行setState,形成无限循环,最终触发最大更新深度的报错。
解决方法
根据你的需求,这里的abc状态是基于abcArray的长度判断的,完全不需要存入state,直接在需要使用的地方计算即可;如果确实需要把这个值存在state里,也要把setState的逻辑移到渲染阶段之外的生命周期方法中:
方案1:直接计算,不使用state
去掉abc状态,直接在需要的地方判断abcArray.length !== 0:
export class ABC extends React.Component { renderOptions() { // 直接返回需要的值,或者这里如果是生成选项逻辑,就正常处理,不要调用setState return abcArray.length !== 0; // 或者根据实际需求返回对应的选项数据 } renderRadio() { return ( <Field id="abc" name="abc" values={this.renderOptions()} /> ); } render() { return ( <div> {this.renderRadio()} </div> ); } } export default connect(mapStateToProps)(ABC);
方案2:在生命周期中更新state(如果确实需要state存储)
如果必须把这个值存在state里,就在组件挂载或abcArray变化时更新状态,不要在render阶段调用:
export class ABC extends React.Component { constructor(props) { super(props); this.state = { abc: abcArray.length !== 0 }; } // 组件挂载完成后更新(如果abcArray是props传递的,还要在componentDidUpdate里处理) componentDidMount() { this.setState({ abc: abcArray.length !== 0 }); } // 如果abcArray是从props获取的,还要监听props变化更新state componentDidUpdate(prevProps) { if (prevProps.abcArray !== this.props.abcArray) { this.setState({ abc: this.props.abcArray.length !== 0 }); } } renderOptions() { // 这里返回需要给Field的values值,比如基于state.abc的逻辑 return this.state.abc; } renderRadio() { return ( <Field id="abc" name="abc" values={this.renderOptions()} /> ); } render() { return ( <div> {this.renderRadio()} </div> ); } } export default connect(mapStateToProps)(ABC);
注意:如果abcArray是通过Redux的mapStateToProps传递的props,一定要在componentDidUpdate里对比前后props的变化再更新state,避免不必要的重渲染。
内容的提问来源于stack exchange,提问作者aki

