React如何更新深层嵌套state?数独项目修改props.children只读报错求助
错误根源
- 不应该将JSX元素直接存入state。React生成的JSX元素的props是不可变的只读属性,直接修改
this.state.board[index].props.children必然触发只读报错 - 不要直接操作DOM修改innerHTML,React是数据驱动视图的框架,所有视图变化都应该通过修改状态、让React自动重渲染完成,直接改DOM会导致DOM和state数据不同步,后续状态更新还会覆盖你手动修改的内容
正确实现思路
state只存棋盘的纯数字数据,不要提前生成JSX,JSX渲染逻辑放到render方法中,每次状态更新时React会自动根据最新数据重新渲染棋盘内容。
具体修改步骤
- 修改接口请求逻辑,state仅存储纯数据:
axios.get("http://127.0.0.1:5000/new-board") .then(response => { console.log("API Response: ", response) this.setState({ boardData: response.data, // 直接存储接口返回的二维数字数组 winningBoard: response.data.map(row => [...row]), // 深拷贝答案数组用于后续胜负校验 gameWon: false }) })
- 将JSX生成逻辑移到render方法中:
render() { const { boardData } = this.state; const board = []; for (let i = 0; i < 9; i++) { let letter = String.fromCharCode(97 + i) for (let j = 0; j < 9; j++) { let column = j + 1; let number = dictionary[j + 1]; let letnum = letter + " " + number + " tile"; let letcol = letter + column; board.push( <div className={letnum} key={letcol} id={letcol} onClick={() => this.handleTileClick(i,j)}> {boardData[i][j]} </div> ) } } // 其余渲染逻辑,将board插入对应节点即可 return <div className="sudoku-board">{board}</div> }
- 修改点击事件逻辑,通过更新状态自动修改视图:
handleTileClick(row, col) { if (!this.state.activeNumberSelector) return; // 深拷贝原棋盘数据,避免直接修改state const newBoardData = this.state.boardData.map(row => [...row]); // 更新对应位置的数字 newBoardData[row][col] = this.state.activeNumberSelector; this.setState({ boardData: newBoardData, activeNumberSelector: '' }, () => { // 可在此处添加胜负校验逻辑,对比newBoardData和winningBoard即可 }) }
额外优化点
- 生成JSX时直接将行列索引传给点击事件,无需通过DOM id反向查找位置,性能更高也避免查找错误
- 可以给初始给定的数字加不可修改标记,点击时跳过修改逻辑,符合数独规则
- handleNumberChoiceClick建议直接将数字作为参数传入,不要读取DOM innerHTML,避免内容解析错误
内容的提问来源于stack exchange,提问作者user13420012
相关产品推荐
相关产品推荐

