Javascript ReactJS:超出最大更新深度错误
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/48497358/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
ReactJS: Maximum update depth exceeded error
提问by Maja Okholm
I am trying to toggle the state of a component in ReactJS but I get an error stating:
我试图在 ReactJS 中切换组件的状态,但我收到一条错误消息:
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.
超出最大更新深度。当组件在 componentWillUpdate 或 componentDidUpdate 中重复调用 setState 时,就会发生这种情况。React 限制嵌套更新的数量以防止无限循环。
I don't see the infinite loop in my code, can anyone help?
我在我的代码中没有看到无限循环,有人可以帮忙吗?
ReactJS component code:
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;
回答by Ali
that because you calling toggle inside the render method which will cause to re-render and toggle will call again and re-rendering again and so on
那是因为您在渲染方法中调用 toggle 将导致重新渲染和 toggle 将再次调用并再次重新渲染等等
this line at your code
在您的代码中的这一行
{<td><span onClick={this.toggle()}>Details</span></td>}
you need to make onClickrefer to this.togglenot calling it
你需要onClick参考this.toggle不调用它
to fixthe issue do this
要解决此问题,请执行此操作
{<td><span onClick={this.toggle}>Details</span></td>}
回答by Florent Philippe
You should pass the event object when calling the function :
您应该在调用函数时传递事件对象:
{<td><span onClick={(e) => this.toggle(e)}>Details</span></td>}
If you don't need to handle onClick event you can also type :
如果您不需要处理 onClick 事件,您还可以输入:
{<td><span onClick={(e) => this.toggle()}>Details</span></td>}
Now you can also add your parameters within the function.
现在您还可以在函数中添加参数。
回答by Piyush N
Forget about the react first:
This is not related to react and let us understand the basic concepts of Java Script. For Example you have written following function in java script (name is A).
先忘掉react:
这个和react无关,让我们了解一下Java Script的基本概念。例如,您在 java 脚本中编写了以下函数(名称为 A)。
function a() {
};
Q.1) How to call the function that we have defined?
Ans: a();
Q.1) 如何调用我们定义的函数?
答:a();
Q.2) How to pass reference of function so that we can call it latter?
Ans: let fun = a;
Q.2) 如何传递函数的引用以便我们可以在后面调用它?
Ans: 让乐趣 = a;
Now coming to your question, you have used paranthesis with function name, mean that function will be called when following statement will be render.
现在来回答你的问题,你已经使用了函数名的括号,这意味着在渲染以下语句时将调用该函数。
<td><span onClick={this.toggle()}>Details</span></td>
Then How to correct it?
Simple!! Just remove parenthesis. By this way you have given the reference of that function to onClick event. It will call back your function only when your component is clicked.
那怎么改正呢?
简单的!!去掉括号就行了。通过这种方式,您已将该函数的引用提供给 onClick 事件。仅当您的组件被单击时,它才会回调您的函数。
<td><span onClick={this.toggle}>Details</span></td>
One suggestion releated to react:
Avoid using inline function as suggested by someone in answers, it may cause performance issue.
Avoid following code, It will create instance of same function again and again whenever function will be called (lamda statement creates new instance every time).
Note:and no need to pass event (e) explicitly to the function. you can access it with in the function without passing it.
与反应相关的一项建议:
避免使用有人在答案中建议的内联函数,这可能会导致性能问题。避免使用以下代码,每当调用函数时,它都会一次又一次地创建相同函数的实例(lamda 语句每次都会创建新实例)。
注意:不需要将事件 (e) 显式传递给函数。您可以在函数中访问它而无需传递它。
{<td><span onClick={(e) => this.toggle(e)}>Details</span></td>}
https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578
https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578
回答by DanteTheSmith
I know this has plenty of answers but since most of them are old (well, older), none is mentioning approach I grow very for of really quick. In short:
我知道这有很多答案,但由于它们中的大多数都是旧的(好吧,旧的),没有人提到我非常快速地成长的方法。简而言之:
Use functional components and hooks.
使用功能组件和钩子。
In longer:
在更长的时间:
Try to use as much functional components instead class ones especially for rendering, AND try to keep them as pure as possible (yes, data is dirty by default I know).
尝试使用尽可能多的功能组件而不是类组件,特别是用于渲染,并尽量保持它们的纯净(是的,我知道默认情况下数据是脏的)。
Two bluntly obvious benefits of functional components (there are more):
功能组件有两个显而易见的好处(还有更多):
- Pureness or near pureness makes debugging so much easier
- Functional components remove the need for constructor boiler code
- 纯净度或接近纯净度使调试变得更加容易
- 功能组件消除了对构造函数锅炉代码的需要
Quick proof for 2nd point - Isn't this absolutely disgusting?
快速证明第二点 - 这不是绝对恶心吗?
constructor(props) {
super(props);
this.toggle= this.toggle.bind(this);
this.state = {
details: false
}
}
If you are using functional components for more then rendering you are gonna need the second part of great duo - hooks. Why are they better then lifecycle methods, what else can they do and much more would take me a lot of space to cover so I recommend you to listen to the man himself: Dan preaching the hooks
如果您正在使用功能组件进行渲染,那么您将需要伟大的二人组的第二部分 - 钩子。为什么它们比生命周期方法更好,它们还能做什么等等会占用我很多篇幅,所以我建议你听听他本人的声音:Dan 讲授钩子
In this case you need only two hooks:
在这种情况下,您只需要两个钩子:
A callback hook conveniently named useCallback. This way you are preventing the binding the function over and over when you re-render.
方便地命名的回调钩子useCallback。这样您就可以防止在重新渲染时一遍又一遍地绑定函数。
A state hook, called useState, for keeping the state despite entire component being function and executing in its entirety (yes, this is possible due to magic of hooks). Within that hook you will store the value of toggle.
一个状态钩子,称为useState,用于保持状态,尽管整个组件都在运行并完整地执行(是的,由于钩子的魔力,这是可能的)。在该钩子中,您将存储 toggle 的值。
If you read to this part you probably wanna see all I have talked about in action and applied to original problem. Here you go: Demo
如果你读到这部分,你可能想看到我在行动中谈到并应用于原始问题的所有内容。给你: 演示
For those of you that want only to glance the component and WTF is this about, here you are:
对于那些只想看一眼组件和 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: I wrote this in case many people landing here with similar problem. Hopefully they will like what they see at least well enough to google it a bit more. This is not me saying other answers are wrong, this is me saying that since the time they have been written, there is another way (IMHO, a better one) of dealing with this.
PS:我写这个以防很多人登陆这里遇到类似的问题。希望他们会喜欢他们所看到的至少足够多的谷歌搜索。这不是我说其他答案是错误的,而是我说自从它们被编写以来,有另一种方法(恕我直言,更好的方法)来处理这个问题。
回答by Abolfazl Miadian
if you don't need to pass arguments to function, just remove () from function like below:
如果您不需要将参数传递给函数,只需从函数中删除 (),如下所示:
<td><span onClick={this.toggle}>Details</span></td>
but if you want to pass arguments, you should do like below:
但是如果你想传递参数,你应该像下面这样:
<td><span onClick={(e) => this.toggle(e,arg1,arg2)}>Details</span></td>
回答by Rizo
ReactJS: Maximum update depth exceeded error
ReactJS:超出最大更新深度错误
inputDigit(digit){
this.setState({
displayValue: String(digit)
})
<button type="button"onClick={this.inputDigit(0)}>
why that?
为什么?
<button type="button"onClick={() => this.inputDigit(1)}>1</button>
The function onDigit sets the state, which causes a rerender, which causes onDigit to fire because that's the value you're setting as onClick which causes the state to be set which causes a rerender, which causes onDigit to fire because that's the value you're… Etc
函数 onDigit 设置状态,这会导致重新渲染,这会导致 onDigit 触发,因为这是您设置为 onClick 的值,这会导致设置导致重新渲染的状态,这会导致 onDigit 触发,因为这是您的值重新……等
回答by Amazing Apps
1.If we want to pass argument in the call then we need to call the method like below
As we are using arrow functions no need to bind the method in cunstructor.
1.如果我们想在调用中传递参数,那么我们需要调用如下方法因为我们使用箭头函数不需要绑定方法cunstructor。
onClick={() => this.save(id)}
when we bind the method in constructor like this
当我们像这样在构造函数中绑定方法时
this.save= this.save.bind(this);
then we need to call the method without passing any argument like below
然后我们需要在不传递任何参数的情况下调用该方法,如下所示
onClick={this.save}
and we try to pass argument while calling the function as shown below then error comes like maximum depth exceeded.
并且我们尝试在调用函数时传递参数,如下所示,然后错误就像超出了最大深度。
onClick={this.save(id)}
回答by Badri Paudel
In this case , this code
在这种情况下,此代码
{<td><span onClick={this.toggle()}>Details</span></td>}
causes toggle function to call immediately and re render it again and again thus making infinite calls.
导致切换函数立即调用并一次又一次地重新渲染它,从而进行无限调用。
so passing only the reference to that toggle method will solve the problem.
所以只传递对该切换方法的引用将解决问题。
so ,
所以 ,
{<td><span onClick={this.toggle}>Details</span></td>}
will be the solution code.
将是解决方案代码。
If you want to use the () , you should use an arrow function like this
如果你想使用 () ,你应该使用这样的箭头函数
{<td><span onClick={()=> this.toggle()}>Details</span></td>}
In case you want to pass parameters you should choose the last option and you can pass parameters like this
如果你想传递参数,你应该选择最后一个选项,你可以像这样传递参数
{<td><span onClick={(arg)=>this.toggle(arg)}>Details</span></td>}
In the last case it doesn't call immediately and don't cause the re render of the function, hence avoiding infinite calls.
在最后一种情况下,它不会立即调用并且不会导致函数的重新渲染,从而避免了无限调用。
回答by makkagru
onClick you should call function, thats called your function toggle.
onClick 你应该调用函数,这就是调用你的函数切换。
onClick={() => this.toggle()}
onClick={() => this.toggle()}

