React战舰游戏useEffect添加newLayout依赖触发无限重渲染如何修复?
React战舰游戏useEffect依赖警告修复方案
问题根源
你出现这个问题的核心原因是newLayout变量的声明位置错误,触发了渲染死循环:
- 原代码控制台抛出的警告如下:
React Hook useEffect has a missing dependency: 'newLayout'. Either include it or remove the dependency array react-hooks/exhaustive-deps
newLayout = [...layout]写在组件顶层,每次组件渲染都会生成一个全新的数组引用- 如果你把它加入useEffect依赖数组,每次渲染都会触发useEffect执行,useEffect内部调用
setLayout更新layout状态后会再次触发组件渲染,形成无限循环,最终导致应用崩溃 - 而不加入依赖的话,就会触发上述的缺失依赖警告
修复方案
所有布局生成用到的临时变量全部放到useEffect内部,不需要依赖外部的layout和newLayout变量,修复后的代码如下:
const ComputerBoard = ({ COLUMNS, ROWS }) => { const [layout, setLayout] = useState(new Array(ROWS * COLUMNS).fill('empty')); useEffect(() => { // 新布局数组移到useEffect内部初始化 const newLayout = new Array(ROWS * COLUMNS).fill('empty'); const checkIfShipFits = (isHorizontal, spaces, i) => { let temp = 0; const x = i % ROWS; const y = Math.floor(i / COLUMNS); for (let n = 0; n < spaces; n += 1) { if (isHorizontal) { if (x + spaces < COLUMNS && newLayout[i + n] !== 'ship') { temp += 1; } } if (!isHorizontal) { if (y + spaces < ROWS && newLayout[i + COLUMNS * n] !== 'ship') { temp += 1; } } } return temp === spaces; }; const generateComputerLayout = () => { const totalShips = computerShipsAvaibles; const boardSize = ROWS * COLUMNS; // 遍历所有战舰类型 for (let j = 0; j < totalShips.length; j += 1) { // 遍历对应类型战舰的生成数量 for (let k = 0; k < totalShips[j].amount; k += 1) { let i = generateRandomIndex(boardSize); const isHorizontal = generateRandomDirection(); while (!checkIfShipFits(isHorizontal, totalShips[j].spaces, i)) { i = generateRandomIndex(boardSize); } for (let l = 0; l < totalShips[j].spaces; l += 1) { if (isHorizontal) newLayout[i + l] = 'ship'; if (!isHorizontal) newLayout[i + COLUMNS * l] = 'ship'; } } } setLayout(newLayout); }; generateComputerLayout(); }, [COLUMNS, ROWS]); return ( <div> <h3>Computer</h3> <div className='board'> {layout.map((square, index) => ( <div // eslint-disable-next-line react/no-array-index-key key={index} className={`square ${square} computer`} /> ))} </div> </div> ); };
核心修改说明
- 删除了组件顶层的
newLayout声明,避免生成额外的外部依赖,同时移除了原代码中无用的随机数生成语句 - 在useEffect内部初始化空白布局数组,所有生成逻辑用到的变量都在effect作用域内,不需要依赖外部状态
- 修复后useEffect的依赖只有
COLUMNS和ROWS,完全符合hooks规则,既不会触发警告,也不会出现死循环,只会在组件挂载、或者行列数变化的时候重新生成电脑方战舰布局
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

