在React中, 对于组件事件的绑定是有很大的坑的.
比如经常会报如下这种错误: Warning: setState(...): Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`.
这种错误引起的原因是在事件绑定的位置直接使用了方法, 而不是调用的匿名函数.
比如如下这样就会报错:
<button className="btn btn-default"
disabled={submitting} onClick={
editStop(form)
} >
<i className="fa fa-ban"/> 取消
</button>
解决方法:
<button className="btn btn-default"
disabled={submitting} onClick={()=>{
editStop(form)
}} >
<i className="fa fa-ban"/> 取消
</button>
注意, 在onclick的地方, 我们把直接放上去的函数onClick={editStop(form)}
改为了使用匿名函数来调用onClick={()=>{editStop(form)}
也就是说使用一个函数将我们的onclick函数句柄包裹起来.
还可以看一下下面的例子:
class ErrorSimulation extends React.Component {
constructor(props) {
super(props);
this.state = {
x : 1
};
}
sayHello(){
console.log("sayHello");
}
_changeValue(newValue){
console.log("_changeValue invoke!");
//你会发现虽然我们没有点击下面的超链接,但是这里会无限打印log,所以说react会自动执行下面的onClick表达式,从而得到真正的onclick函数句柄,
//进而导致无限修改state与reRender,直到内存溢出。因此可以是onClick={this._changeValue.bind(2)}或者onClick={()=>{this._changeValue(2)}},
//后者当react执行onClick表达式的时候得到的是一个函数
this.setState({newValue});
}
render() {
return (
<div>
<a onClick={this._changeValue.bind(2)}>Change Value</a>
<a onClick={this.sayHello()}>sayHello</a>
</div>
)
}
}
ReactDOM.render(
<ErrorSimulation name="World" />,
document.getElementById('container')
);
参考资料:最重要的一篇 Why does this error exist: “Invariant Violation: Cannot update during an existing state transition” setState(...): Cannot update during an existing state transition
总结: 你可以看到,我们的第二个a标签我们onClick是直接调用了函数,所以会导致无限渲染元素,导致内存溢出。而第一个a标签,我们使用了bind,所以必须点击才能触发,这才是我们想要的结果。
网友评论