React开发井字棋游戏时遇TypeError读取未定义属性错误
问题分析
点击方块后页面空白并报错,核心原因有两个:
- 状态更新破坏数组结构:App组件中
square是数组类型,但Square组件调用setSquare时直接传入单个对象,替换了原本的数组。后续App尝试访问square[0]时会得到undefined,导致Square组件接收的square为undefined,访问square.value就触发报错。 - 初始数组元素引用重复:使用
Array(9).fill({value: null, isClick: false})创建数组时,所有元素都是同一个对象的引用,后续修改任意一个元素会意外影响其他方块的状态。
修复后的完整代码
import React, { useState } from "react"; const App = () => { const [turn, setTurn] = useState(false); // 用Array.from创建独立对象的数组,避免引用重复 const [square, setSquare] = useState(Array.from({length:9}, () => ({value: null, isClick: false}))) return ( <div> <h1>Turn: {turn ? "O" : "X"}</h1> <div className="board-row"> {/* 给每个Square传递index,明确修改的是哪个位置的方块 */} <Square turn={turn} setTurn={setTurn} square={square[0]} setSquare={setSquare} index={0} /> <Square turn={turn} setTurn={setTurn} square={square[1]} setSquare={setSquare} index={1} /> <Square turn={turn} setTurn={setTurn} square={square[2]} setSquare={setSquare} index={2} /> </div> <div className="board-row"> <Square turn={turn} setTurn={setTurn} square={square[3]} setSquare={setSquare} index={3} /> <Square turn={turn} setTurn={setTurn} square={square[4]} setSquare={setSquare} index={4} /> <Square turn={turn} setTurn={setTurn} square={square[5]} setSquare={setSquare} index={5} /> </div> <div className="board-row"> <Square turn={turn} setTurn={setTurn} square={square[6]} setSquare={setSquare} index={6} /> <Square turn={turn} setTurn={setTurn} square={square[7]} setSquare={setSquare} index={7} /> <Square turn={turn} setTurn={setTurn} square={square[8]} setSquare={setSquare} index={8} /> </div> </div> ); }; export default App; const Square = ({ turn, setTurn, square, setSquare, index }) => { const clickHandle = () => { if (!square.isClick) { // 复制原数组,修改对应索引的元素,保持数组结构 setSquare(prev => { const newSquare = [...prev]; newSquare[index] = {value: turn ? "O" : "X", isClick: true}; return newSquare; }); setTurn(!turn); } }; return ( <div> <button className="square" onClick={clickHandle}> {square.value} </button> </div> ); };
关键修复点
- 传递索引标识位置:给每个Square组件添加
index属性,明确当前方块在数组中的位置。 - 正确更新数组状态:使用函数式更新
setSquare(prev => ...),先复制原数组,再修改对应索引的元素,确保状态始终是数组类型。 - 初始化独立元素数组:用
Array.from替代fill,创建9个独立的对象,避免引用共享导致的意外状态变更。
内容的提问来源于stack exchange,提问作者dtnwen
相关产品推荐
相关产品推荐

