React Material-UI中onClick触发无限循环的原因及解决方法
为什么会出现无限循环?怎么解决?
嘿,这个问题我之前也碰到过,其实核心原因很简单——你在JSX里给onClick传的是函数调用的结果,而不是函数本身!
问题根源
当组件执行render时,JSX会被逐一解析执行。你写的onClick={this.handleToggle(item.id)}会立即调用handleToggle(item.id),而你的handleToggle函数里又调用了setState——setState会触发组件重新render,新的render又会再次调用handleToggle,如此往复就形成了无限循环的死循环。
解决方案
这里给你三种常用的解决思路,你可以根据场景选择:
1. 用箭头函数包裹(最简单直接)
把onClick改成箭头函数,这样只有当点击事件触发时才会调用handleToggle,而不是在render时立即执行:
<ListItem onClick={() => this.handleToggle(item.id)}> {/* 列表项内容 */} </ListItem>
这种方法的缺点是每次render都会创建一个新的箭头函数,不过在列表项数量不多的场景下,性能影响可以忽略不计。
2. 柯里化你的处理函数
把handleToggle改成一个返回函数的函数,这样调用this.handleToggle(item.id)时会返回一个待执行的函数,而不是立即执行逻辑:
// 先确保在构造函数绑定this,或者使用类箭头函数 handleToggle = (value) => () => { if (this.state.isLoading) { return; } const { checked } = this.state; const currentIndex = checked.indexOf(value); const newSelected = checked.slice(); // 补全你的选中状态切换逻辑 if (currentIndex !== -1) { newSelected.splice(currentIndex, 1); } else { newSelected.push(value); } this.setState({ checked: newSelected }); }
然后在JSX里直接使用:
<ListItem onClick={this.handleToggle(item.id)}> {/* 列表项内容 */} </ListItem>
3. 使用DOM自定义属性传递参数
通过data-*属性把item.id绑定到DOM元素上,然后在handleToggle里通过事件对象获取参数,避免每次创建新函数:
<ListItem onClick={this.handleToggle} data-id={item.id}> {/* 列表项内容 */} </ListItem>
修改handleToggle函数:
handleToggle = (event) => { if (this.state.isLoading) { return; } // 从事件对象中获取id const value = event.target.dataset.id; const { checked } = this.state; const currentIndex = checked.indexOf(value); const newSelected = checked.slice(); // 补全你的选中状态切换逻辑 if (currentIndex !== -1) { newSelected.splice(currentIndex, 1); } else { newSelected.push(value); } this.setState({ checked: newSelected }); }
这种方法性能最优,适合列表项数量较多的场景。
内容的提问来源于stack exchange,提问作者O.Voronin
相关产品推荐
相关产品推荐

