React井字棋状态更新异常:数组状态已更新但HTML未渲染
React井字棋状态更新后不重新渲染的问题解决
问题根源
你遇到的核心问题是直接原地修改了状态数组,React的状态更新依赖引用变化触发重渲染:
- 在
Box.js的handleClick里,const updatedArray = prevArr只是把原数组的引用赋值给新变量,修改updatedArray[props.index]本质是修改原状态数组,数组引用没发生变化。 - React对数组/对象类型的状态做浅比较,发现引用没变就判定状态未更新,不会触发组件重渲染。
- 另外
Board.js里的isXTurn状态解构有误,多了个逗号,导致setIsXTurn没正确获取到状态更新函数,后续玩家切换会失效。
修复方案
- 修改数组状态时创建副本:更新arr状态时先复制原数组的副本,修改副本后再返回,确保引用变化。
- 修正状态解构错误:把
const [isXTurn, ,setIsXTurn]改成const [isXTurn, setIsXTurn]。 - 点击后切换玩家:更新完arr状态后,调用
setIsXTurn切换玩家回合。
修正后的完整代码
Board.js
import React from 'react' import Box from './Box' import './Board.css' function Board() { // 初始化9格空棋盘 const [arr, setArr] = React.useState(Array(9).fill(null)) // 当前玩家是否为X(修正解构错误) const [isXTurn, setIsXTurn] = React.useState(true) // 整合props const props = { arr, setArr, isXTurn, setIsXTurn } // 生成Box元素列表 const arrayEle = arr.map((ele, i) => (<Box {...props} value={ele} index={i} key={i}/>)) return ( <div className='board'> {arrayEle} {/* 用JSON.stringify展示数组状态,方便调试 */} {JSON.stringify(arr)} </div> ); } export default Board;
Box.js
import React from 'react' import './Box.css' function Box(props) { // 根据值设置样式 const style = props.value === 'X' ? 'box x' : 'box o' function handleClick(){ // 已填充的格子不能点击 if(props.value) return props.setArr(prevArr => { // 创建原数组的副本(关键:避免原地修改) const updatedArray = [...prevArr] updatedArray[props.index] = props.isXTurn ? 'X' : 'O' return updatedArray }) // 切换玩家回合 props.setIsXTurn(prev => !prev) } return ( <button className={style} onClick={handleClick}> {props.value} </button> ); } export default Box;
补充说明
- 创建数组副本的方式不止扩展运算符,还可以用
Array.from(prevArr)或者prevArr.slice(),核心都是不修改原状态数组。 - 切换玩家时用
setIsXTurn(prev => !prev)这种函数式更新更安全,避免依赖外部异步的isXTurn值。
内容的提问来源于stack exchange,提问作者Shaan Shimpi
相关产品推荐
相关产品推荐

