ReactJS:超出最大更新深度错误

IT技术 javascript reactjs react-native
2021-01-28 18:39:21

我试图在 ReactJS 中切换组件的状态,但我收到一条错误消息:

超出最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,就会发生这种情况。React 限制嵌套更新的数量以防止无限循环。

我在我的代码中没有看到无限循环,有人可以帮忙吗?

ReactJS 组件代码:

import React, { Component } from 'react';
import styled from 'styled-components';

class Item extends React.Component {
    constructor(props) {
        super(props);     
        this.toggle= this.toggle.bind(this);
        this.state = {
            details: false
        } 
    }  
    toggle(){
        const currentState = this.state.details;
        this.setState({ details: !currentState }); 
    }

    render() {
        return (
            <tr className="Item"> 
                <td>{this.props.config.server}</td>      
                <td>{this.props.config.verbose}</td> 
                <td>{this.props.config.type}</td>
                <td className={this.state.details ? "visible" : "hidden"}>PLACEHOLDER MORE INFO</td>
                {<td><span onClick={this.toggle()}>Details</span></td>}
            </tr>
    )}
}

export default Item;
6个回答

那是因为您在渲染方法中调用 toggle 将导致重新渲染和 toggle 将再次调用并再次重新渲染等等

在您的代码中的这一行

{<td><span onClick={this.toggle()}>Details</span></td>}

你需要onClick参考this.toggle不调用它

解决此问题,请执行此操作

{<td><span onClick={this.toggle}>Details</span></td>}
@iWillGetBetter 是的 onClick 中的第一个参数是点击事件。如果您需要额外的参数,您也可以传递它onClick={(event) => this.toggle(event, myParam)}
2021-03-17 18:39:21
我也面临类似的情况,但是我需要传递一个参数来切换,如何实现?
2021-03-29 18:39:21
@FabianPicone 尝试了您的方法,但是当我在 console.log 中显示“param”作为事件传递时,实际上应该这样做 onClick={() => this.toggle(param)}
2021-03-31 18:39:21
我有这个函数closeEditModal = () => this.setState({openEditModal: false});如何在渲染中调用它?
2021-04-04 18:39:21
@NivedithaKarmegam 做onClick={(param) => this.toggle(param)}这不会立即触发(并重新渲染)。这是一个回调定义(箭头函数)。
2021-04-06 18:39:21

您应该在调用函数时传递事件对象:

{<td><span onClick={(e) => this.toggle(e)}>Details</span></td>}

如果您不需要处理 onClick 事件,您还可以输入:

{<td><span onClick={(e) => this.toggle()}>Details</span></td>}

现在您还可以在函数中添加参数。

{<td><span onClick={() => this.toggle(whateverParameter)}>Details</span></td>} 对我有用
2021-03-23 18:39:21
由于与事件对象无关的噪音而被否决。
2021-03-29 18:39:21
如果未指定任何内容,将自动发送事件对象。只需在被调用的函数中包含一个输入参数。
2021-04-09 18:39:21

先忘掉react:
这个和react无关,让我们了解一下Java Script的基本概念。例如,您在 java 脚本中编写了以下函数(名称为 A)。

function a() {

};

Q.1) 如何调用我们定义的函数?
答:a();

Q.2) 如何传递函数的引用以便我们可以在后面调用它?
Ans: 让乐趣 = a;

现在来回答你的问题,你在函数名中使用了括号,这意味着在渲染以下语句时将调用该函数。

<td><span onClick={this.toggle()}>Details</span></td>

那么如何纠正呢?
简单的!!去掉括号就行了。通过这种方式,您已将该函数的引用提供给 onClick 事件。仅当您的组件被单击时,它才会回调您的函数。

 <td><span onClick={this.toggle}>Details</span></td>

与react相关的一个建议:
避免使用有人在答案中建议的内联函数,这可能会导致性能问题。避免以下代码,每当函数被调用时,它会一次又一次地创建相同函数的实例(lamda 语句每次都会创建新实例)。
注意:并且不需要将事件 (e) 显式传递给函数。您可以在函数中访问它而无需传递它。

{<td><span onClick={(e) => this.toggle(e)}>Details</span></td>}

https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578

我知道这有很多答案,但由于它们中的大多数都是旧的(好吧,旧的),没有提到我非常喜欢的方法。简而言之:

使用功能组件和钩子

在更长的时间:

尝试使用尽可能多的功能组件而不是类组件,特别是用于渲染,并尽量保持它们的纯净(是的,我知道默认情况下数据是脏的)。

功能组件有两个显而易见的好处(还有更多):

  • 纯净或接近纯净使调试变得更加容易
  • 功能组件消除了对构造函数锅炉代码的需要

快速证明第二点 - 这不是绝对恶心吗?

constructor(props) {
        super(props);     
        this.toggle= this.toggle.bind(this);
        this.state = {
            details: false
        } 
    }  

如果您正在使用功能组件进行渲染,那么您将需要伟大的二人组的第二部分 - 钩子。为什么它们比生命周期方法更好,它们还能做什么以及更多会占用我很多篇幅,所以我建议你听听他本人的声音:Dan 讲授钩子

在这种情况下,您只需要两个钩子:

方便地命名的回调挂钩useCallback通过这种方式,您可以防止在重新渲染时一遍又一遍地绑定函数。

一个状态钩子,称为useState,用于保持状态,尽管整个组件都在运行并完整地执行(是的,由于钩子的魔力,这是可能的)。在该钩子中,您将存储 toggle 的值。

如果你读到这部分,你可能想看到我在行动中谈到的并应用于原始问题的所有内容。给你: 演示

对于那些只想看一眼组件和 WTF 的人来说,这里是:

const Item = () => {

    // HOOKZ
  const [isVisible, setIsVisible] = React.useState('hidden');

  const toggle = React.useCallback(() => {
    setIsVisible(isVisible === 'visible' ? 'hidden': 'visible');
  }, [isVisible, setIsVisible]);

    // RENDER
  return (
  <React.Fragment>
    <div style={{visibility: isVisible}}>
        PLACEHOLDER MORE INFO
    </div>
    <button onClick={toggle}>Details</button>
  </React.Fragment>
  )
};

PS:我写这个是为了防止很多人遇到类似问题。希望他们会喜欢我在这里展示的内容,至少足以让他们多用谷歌搜索一下。这不是我说其他答案是错误的,这是我说自从它们被编写以来,有另一种方法(恕我直言,更好的方法)来处理这个问题。

如果您不需要将参数传递给函数,只需从函数中删除 (),如下所示:

<td><span onClick={this.toggle}>Details</span></td>

但是如果你想传递参数,你应该像下面这样:

<td><span onClick={(e) => this.toggle(e,arg1,arg2)}>Details</span></td>