React.js中使用setState时页面自动重载重置该如何解决?
问题原因
- 你直接用原生
innerHTML操作DOM修改格子内容,这部分修改没有同步到React的状态中。当你调用setState时,React会触发组件重新渲染,会按照return里的模板重新生成DOM结构,你手动修改的原生DOM内容自然就被重置了。 - 你的棋盘格子状态没有存储在React状态里,组件重渲染时没有数据源可以保留之前的落子记录。
- 目前的落子逻辑和状态更新是割裂的,玩家切换、回合数更新没有和落子行为绑定。
修复方案
1. 重构状态结构
把棋盘的落子数据也加入state,用长度为9的数组或者3x3的二维数组存储每个格子的内容,后续所有落子、玩家切换都通过修改state实现,完全不要手动操作DOM。
2. 调整落子和渲染逻辑
所有格子的内容从state中读取,点击格子时只修改state对应位置的数值,由React自动负责视图更新。
修正后的代码示例
<script type="text/babel"> // 单独抽离格子组件 function Column({ value, onClick }) { return <div className="column" onClick={onClick}> {value && <h1 className="symbols">{value}</h1>} </div> } // 抽离行组件,传入当前行的三个格子数据和点击回调 function CreateRow({ rowData, onColumnClick }) { return <div className="row"> {rowData.map((val, idx) => <Column key={idx} value={val} onClick={() => onColumnClick(idx)} />)} </div> } function Heading() { return <h1>井字棋</h1> } function TicTacToe() { const [state, setState] = React.useState({ turn: 0, player: 'player1', // 3x3棋盘状态,初始为空 board: Array(3).fill(null).map(() => Array(3).fill(null)) }); function columnClicked(rowIdx, colIdx) { // 已经落子的格子不能再改 if (state.board[rowIdx][colIdx]) return const newBoard = state.board.map(row => [...row]) newBoard[rowIdx][colIdx] = state.player === 'player1' ? 'X' : 'O' setState({ ...state, board: newBoard, turn: state.turn + 1, player: state.player === 'player1' ? 'player2' : 'player1' }) } return ( <div> <Heading /> <div className='container'> {state.board.map((row, rowIdx) => <CreateRow key={rowIdx} rowData={row} onColumnClick={(colIdx) => columnClicked(rowIdx, colIdx)} /> )} </div> <p>当前玩家:{state.player === 'player1' ? 'X' : 'O'}</p> </div> ); } ReactDOM.render(<TicTacToe />, document.getElementById('tic_tac_toe')); </script>
核心改动说明
- 移除了所有手动操作DOM的逻辑,所有视图内容都由state驱动渲染,调用
setState后重渲染会保留所有落子记录,不会再重置。 - 棋盘状态和玩家、回合数状态都统一管理,落子后自动切换玩家和更新回合数,不需要额外的切换按钮。
- 组件拆分更合理,每个组件只负责对应部分的渲染和事件传递。
内容的提问来源于stack exchange,提问作者Harris Abdullah
相关产品推荐
相关产品推荐

