React StrictMode下组件重复渲染致角色移动翻倍问题求助
问题原因与解决方案
问题根源
你遇到的问题核心不是StrictMode本身,而是状态更新函数违反了React的不可变原则,加上StrictMode的开发模式检测放大了这个问题:
- 在
updatePlayerPos中,你用了prev.pos.x += x这种写法,直接修改了React的前状态对象(prev),属于不纯操作。 - StrictMode在开发环境下会两次执行状态更新的回调函数,目的是检测这类不纯的副作用。第一次执行时已经修改了
prev对象的属性,第二次执行时用的是已经被修改过的prev,所以导致位置变化翻倍。
解决方案
修复的关键是保证状态更新函数是纯函数,绝对不要直接修改prev状态,而是创建新的对象来保存新状态:
修改usePlayer中的updatePlayerPos函数:
import { useState } from 'react'; export const usePlayer = () => { const [player, setPlayer] = useState({ pos: { x: 0, y: 0 }, }); const updatePlayerPos = ({ x, y }) => { console.log('updatePlayerPos'); setPlayer((prev) => ({ ...prev, // 不要修改prev.pos,而是计算新的x/y值,创建新的pos对象 pos: { x: prev.pos.x + x, y: prev.pos.y + y }, })); }; return [updatePlayerPos, player]; };
为什么这样有效
- 这里不再直接修改
prev.pos,而是基于prev.pos.x和传入的x计算出新的x值,创建一个全新的pos对象,保证了状态的不可变性。 - 即使StrictMode两次执行这个更新函数,每次拿到的
prev都是原始的未修改状态,两次执行的结果都是相同的,React会自动忽略第二次重复的更新。
额外注意
- React的状态必须是不可变的,直接修改状态对象不仅会导致StrictMode下的问题,还可能引发组件不重新渲染、状态不一致等难以排查的bug。
- StrictMode是开发环境的工具,帮你提前发现这类问题,上线生产环境后不会有双重执行的情况,但遵循不可变原则是React开发的基础规范。
内容的提问来源于stack exchange,提问作者Zim92
相关产品推荐
相关产品推荐

