如何修复React拼图应用中已卸载组件触发状态更新的报错问题
错误原因
这个报错的本质是组件已经从DOM上卸载后,代码仍然调用了setState尝试更新它的状态。React不会执行这个无效的状态更新,但会抛出该提示,提醒应用存在内存泄漏风险。
你这个场景的触发逻辑是:拼完最后一块拼图时,dropped方法会执行setState({video: true}),触发组件重新渲染后,原先的拼图相关组件(包括你用到的DragDropContainer、DropTarget)都会被卸载,而该拖拽库的onHit回调存在异步触发逻辑,就会出现在组件卸载后仍然尝试调用setState的情况。
修复方法
步骤1:新增组件挂载标记位与生命周期
在Game类中新增挂载标记、componentDidMount和componentWillUnmount生命周期:
export class Game extends Component { // 新增挂载标记 _isMounted = false; state = { video: false, } // 新增生命周期:组件挂载后标记为已挂载 componentDidMount() { this._isMounted = true; } // 新增生命周期:组件卸载前标记为已卸载 componentWillUnmount() { this._isMounted = false; } // 剩下的原有代码... }
步骤2:修改setState调用逻辑
修改dropped方法中的setState调用,执行前先判断组件是否还处于挂载状态:
dropped = e => { e.containerElem.style.visibility = 'hidden'; e.target.classList.add('highlighted'); this.PuzzleCounter++; if (this.PuzzleCounter === 3 && this._isMounted) { this.setState({ video : true, }); } }
可选优化建议
- 你目前把styled组件定义为类的实例属性,每次组件实例化都会重新创建样式组件,建议把这些styled组件移到类的外部定义,能提升渲染性能。
- 后续如果要在视频的
onEnded回调中添加修改组件状态的逻辑,同样需要先判断_isMounted标记位,避免出现同类报错。
内容的提问来源于stack exchange,提问作者Thomas Hewitt
相关产品推荐
相关产品推荐

