我试图在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;

当前回答

我知道这个问题有很多答案,但因为他们大多数都是老的(好吧,更老了),没有人提到我非常喜欢的方法。简而言之:

使用功能组件和钩子。

长:

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

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

纯粹性或接近纯粹性使调试变得更加容易 功能组件不需要构造函数锅炉代码

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

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

如果你使用功能组件进行更多的渲染,你将需要伟大的duo - hook的第二部分。为什么它们比生命周期方法更好,它们还能做什么,以及更多的东西,这将占用我很多空间,所以我建议你听他自己说: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>

我知道这个问题有很多答案,但因为他们大多数都是老的(好吧,更老了),没有人提到我非常喜欢的方法。简而言之:

使用功能组件和钩子。

长:

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

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

纯粹性或接近纯粹性使调试变得更加容易 功能组件不需要构造函数锅炉代码

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

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

如果你使用功能组件进行更多的渲染,你将需要伟大的duo - hook的第二部分。为什么它们比生命周期方法更好,它们还能做什么,以及更多的东西,这将占用我很多空间,所以我建议你听他自己说: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:我写这个是为了防止很多人有类似的问题。希望他们会喜欢我在这里展示的东西,至少好到可以再谷歌一点。这不是我说其他答案是错误的,这是我说,自从它们被写出来以来,有另一种方法(恕我直言,更好的方法)来处理这个问题。

在我的例子中,这是由于无限循环。

我的一个函数是设置状态,组件正在重新加载,该组件依次导致函数重新运行,然后函数再次设置状态。这个循环一直到无穷。

为了避免这种情况,我把我的函数包装在useEffect钩子中,并给它一些依赖,这样这个函数只在依赖被改变时运行。

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

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

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

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

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

这是因为你在渲染方法中调用toggle,这将导致重新渲染,toggle将再次调用,再次重新渲染,等等。

代码中的这一行:

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

你需要使onClick指向这个。切换而不是调用它。

要解决这个问题,请这样做:

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