今天学习React的时候,一不小心踩到了坑,进入了无限死循环,导致直接溢出内存,报错
主要的原因就在于onClick事件中传入带参数的函数,应该传入函数的引用,而并非函数的调用
错误写法:在编写的时候,首在constructor函数中先进行this的绑定
this.toggleBtnClick = this.toggleBtnClick.bind(this);
然后进行onClick函数绑定事件的编写,错误点在为了函数传递参数,而在后面加了小括号。相当于在传参的同时,直接调用了该函数!
<button onClick={this.toggleBtnClick(this.state.isToggleOn)}>
{this.state.isToggleOn ? 'Button On' : 'Button Off'}
</button>
这样的编写逻辑就会导致下面的死循环错误!
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.
错误:超过最大更新深度。当组件在componentWillUpdate或componentDidUpdate内重复调用setState时,就会发生这种情况。React限制嵌套更新的数量,以防止无限循环。
//正确代码如下:
import React, {
Component
} from 'react';
class ToggleBtnComp extends Component {
constructor(props) {
super(props)
this.state = {
isToggleOn: true
}
}
render() {
// console.log(this);
return (
<button onClick={this.toggleBtnClick.bind(this, this.state.isToggleOn)}>
{this.state.isToggleOn ? 'Button On' : 'Button Off'}
</button>
);
}
toggleBtnClick(isToggleOn, e) {
console.log('Now state is' + isToggleOn + ' before to convert.');
this.setState({
isToggleOn: !isToggleOn
})
}
}
export default ToggleBtnComp;
分析一下程序整体执行流程:当组件ToggleBtnComp
在index
中被渲染的时候,相当于new了一个实例,必然会调用constructor
构造函数。其中render
函数属于生命周期函数,也必然会被执行。在render
函数里面必然会解析return
里面的内容。当解析到Button
的时候,发现有一个点击事件。React
框架就会自动解析和执行onClick
里面的代码。如果里面是方法的调用,那么一进行解析,就会执行里面的代码。当我们的代码正在进行解析的时候,绑定点击事件的代码就被执行,显然这样是不合适的。而且在事件函数中我们又使用了setState
,重新更新了状态属性,紧接着再次进行页面的渲染,周而复始,终导致死循环,内存溢出。所以我们应该等到点击按下的时候,再执行里面的函数内容。所以绑定的事件里面应该传入事件的引用,或者利用箭头函数进行书写。
onClick函数里面的两种书写方式
写法1. 传入事件的引用,并进行传参(需要绑定this,否则引用中的this指向调用者button)
<button onClick={this.toggleBtnClick.bind(this,this.state.isToggleOn)}>
{this.state.isToggleOn ? 'Button On' : 'Button Off'}
</button>
写法2. 箭头函数(无需绑定this,在箭头函数中this自然指向ToggleBtnComp)
<button onClick={() => this.toggleBtnClick(this.state.isToggleOn)}>
{this.state.isToggleOn ? 'Button On' : 'Button Off'}
</button>
总结:原先方法的直接调用,导致了setState函数更新状态后,进行render,又会重新触发onClick中函数的调用,从而会不停地进行render渲染。使用以上两种编写方式进行修改后,便可实现最初效果(点击后再进行方法的调用)。