我试图在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;
在本例中,就是这段代码
{<td><span onClick={this.toggle()}>Details</span></td>}
导致切换函数立即调用,并重新呈现它一次又一次,从而进行无限的调用。
因此,只传递对toggle方法的引用就可以解决问题。
所以,
{<td><span onClick={this.toggle}>Details</span></td>}
将是解决方案代码。
如果你想使用(),你应该使用一个像这样的箭头函数
{<td><span onClick={()=> this.toggle()}>Details</span></td>}
如果你想传递参数,你应该选择最后一个选项,你可以这样传递参数
{<td><span onClick={(arg)=>this.toggle(arg)}>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的情况,则
const [isInitialRender, setIsInitialRender] = useState(true);
useEffect(() => {
const data = localStorage.getItem("auth");
如果(isInitialRender) {
setIsInitialRender(假);
If(数据){
const parsed = JSON.parse(data);
setAuth({…认证,用户:已解析。用户,令牌:已解析。令牌});
}
}
}, [auth, isInitialRender]);
isInitialRender true和false将避免你陷入循环
1.如果我们想在调用中传递参数,那么我们需要像下面这样调用方法
因为我们使用的是箭头函数,所以不需要在构造函数中绑定方法。
onClick={() => this.save(id)}
当我们像这样在构造函数中绑定方法时
this.save= this.save.bind(this);
然后,我们需要调用该方法而不传递任何参数,如下所示
onClick={this.save}
我们尝试在调用函数时传递参数
如下所示,然后误差就像最大深度超出。
onClick={this.save(id)}
在本例中,就是这段代码
{<td><span onClick={this.toggle()}>Details</span></td>}
导致切换函数立即调用,并重新呈现它一次又一次,从而进行无限的调用。
因此,只传递对toggle方法的引用就可以解决问题。
所以,
{<td><span onClick={this.toggle}>Details</span></td>}
将是解决方案代码。
如果你想使用(),你应该使用一个像这样的箭头函数
{<td><span onClick={()=> this.toggle()}>Details</span></td>}
如果你想传递参数,你应该选择最后一个选项,你可以这样传递参数
{<td><span onClick={(arg)=>this.toggle(arg)}>Details</span></td>}
在最后一种情况下,它不会立即调用,也不会导致函数的重新呈现,因此避免了无限调用。