React函数组件重渲染触发逻辑及游戏网格组件更新异常问题
问题:棋盘游戏状态更新后GameGrid组件不重渲染
场景说明
我正在开发一款棋盘游戏,流程是在PieceSelection组件选择棋子,再点击GameGrid中的格子完成落子。组件层级结构如下:
Game |- GameGrid | |- Square |- PieceSelection
在Game组件中维护了两个状态:
currDisplay:存储GameGrid当前的棋盘显示内容currSelectedPiece:记录当前选中的棋子
我给每个Square组件传递了点击回调函数,用于在格子被点击时通知Game组件对应的格子ID。Game组件中的落子处理函数如下:
// Inside Game component: function handlePiecePlacement(squareID: number) { // 落子合法性校验... let newDisplay = currDisplay; newDisplay[squareID] = currSelectedPiece; setCurrDisplay(newDisplay); }
这个函数通过props先传给GameGrid,再由GameGrid传递给每个Square组件。
遇到的问题
点击格子调用handlePiecePlacement后,虽然状态看似更新,但GameGrid组件并未重渲染,页面没有可见变化。但另一个处理选中棋子的函数handleClickToSelectPiece却能触发GameGrid重渲染,这两个函数都在Game组件中,为什么会有差异?
选中棋子的处理函数代码:
// Inside Game component: function handleClickToSelectPiece(clicked: string) { setCurrSelectedPiece(clicked); }
原因分析与解决方案
核心原因
React依赖状态的引用变化来触发组件重渲染:
- 在
handlePiecePlacement中,let newDisplay = currDisplay只是复制了原数组/对象的引用,修改newDisplay[squareID]本质是直接修改了原状态对象。之后调用setCurrDisplay传入的还是同一个引用,React会判定状态没有发生变化,因此不会触发GameGrid的重渲染。 - 而
handleClickToSelectPiece中,setCurrSelectedPiece传入的是新的字符串(值类型,每次赋值都会生成新的引用),React能检测到状态变化,进而触发依赖该状态的组件(包括GameGrid)重渲染。
修复代码
根据currDisplay的类型选择对应的副本创建方式:
- 如果
currDisplay是数组:
function handlePiecePlacement(squareID: number) { // 落子合法性校验... // 创建数组的浅副本 let newDisplay = [...currDisplay]; newDisplay[squareID] = currSelectedPiece; setCurrDisplay(newDisplay); }
- 如果
currDisplay是对象:
function handlePiecePlacement(squareID: number) { // 落子合法性校验... // 创建对象的浅副本 let newDisplay = {...currDisplay}; newDisplay[squareID] = currSelectedPiece; setCurrDisplay(newDisplay); }
不需要主动通知GameGrid重渲染,只要保证状态更新时传入新的引用,React会自动检测到GameGrid的display props变化,触发组件重渲染。
内容的提问来源于stack exchange,提问作者crystaltine
相关产品推荐
相关产品推荐

