React开发国际象棋游戏:点击移动时activePiece变量置空问题求助
解决方案
核心问题分析
你当前用let activePiece = null这种普通变量管理选中的棋子,React组件每次渲染时这个变量都会被重置;同时点击棋子时mousedown和mouseup会连续触发,导致movePiece立刻把activePiece设为null,无法保留选中状态。必须改用React的useState管理选中状态,同时区分"选中棋子"和"点击目标位置"两种操作。
具体修改步骤
改用useState管理activePiece
替换普通变量为React状态,确保选中状态在组件渲染间保留:// 替换 let activePiece = null; const [activePiece, setActivePieceState] = useState(null);重写setActivePiece函数
区分两种场景:已有选中棋子时点击棋盘则触发移动,点击棋子则切换选中状态:function setActivePiece(e) { e.preventDefault(); // 点击棋盘:若有选中棋子则移动 if (e.target.id === "boardImg") { activePiece && movePiece(e); return; } // 点击棋子:切换选中状态(点击已选中棋子则取消) const clickedPiece = e.target; setActivePieceState(prev => prev?.id === clickedPiece.id ? null : clickedPiece ); }修改movePiece函数
依赖状态中的activePiece,移动后重置选中状态,且避免直接修改原对象:function movePiece(e) { if (!activePiece) return; const boardRect = boardRef.current.getBoundingClientRect(); const pieceSize = boardRect.width / 8; const targetX = parseInt((e.clientX - boardRect.x) / pieceSize); const targetY = parseInt((e.clientY - boardRect.y) / pieceSize); setPieces(prevState => prevState.map(p => p.id === activePiece.id ? {...p, x: targetX, y: targetY} : p ) ); // 移动完成后清空选中状态 setActivePieceState(null); }修正useEffect的依赖
原代码依赖activePiece会导致每次选中棋子都重新生成棋盘,改为仅在组件挂载时初始化:useEffect(() => { setPieces(generateBoard()); }, []); // 空依赖数组,仅挂载时执行调整拖拽函数dragPiece
改用状态中的activePiece,优化计算逻辑:function dragPiece(e){ if (!activePiece) return; const boardRect = boardRef.current.getBoundingClientRect(); const pieceHalfSize = boardRect.width / 4; activePiece.style.left = `${e.clientX - boardRect.x - pieceHalfSize}px`; activePiece.style.top = `${e.clientY - boardRect.y - pieceHalfSize}px`; }修正Piece组件的key
不要用uuidv4()作为key(每次渲染都会生成新key,导致组件重复卸载挂载),改用棋子的唯一id:pieces.map(piece => <Piece key={piece.id} piece={piece}/>)
最终修改后的完整Board组件代码
import { useState, useRef, useEffect } from 'react'; // 假设已导入boardImg、generateBoard等依赖 function Board(){ const [pieces, setPieces] = useState([]); const [activePiece, setActivePieceState] = useState(null); const boardRef = useRef(); function movePiece(e) { if (!activePiece) return; const boardRect = boardRef.current.getBoundingClientRect(); const pieceSize = boardRect.width / 8; const targetX = parseInt((e.clientX - boardRect.x) / pieceSize); const targetY = parseInt((e.clientY - boardRect.y) / pieceSize); setPieces(prevState => prevState.map(p => p.id === activePiece.id ? {...p, x: targetX, y: targetY} : p ) ); setActivePieceState(null); } function setActivePiece(e) { e.preventDefault(); if (e.target.id === "boardImg") { activePiece && movePiece(e); return; } const clickedPiece = e.target; setActivePieceState(prev => prev?.id === clickedPiece.id ? null : clickedPiece ); } function dragPiece(e){ if (!activePiece) return; const boardRect = boardRef.current.getBoundingClientRect(); const pieceHalfSize = boardRect.width / 4; activePiece.style.left = `${e.clientX - boardRect.x - pieceHalfSize}px`; activePiece.style.top = `${e.clientY - boardRect.y - pieceHalfSize}px`; } useEffect(() => { setPieces(generateBoard()); }, []); return( <div id="board" onMouseDown={setActivePiece} onMouseUp={movePiece} onMouseMove={dragPiece} > <img ref={boardRef} id="boardImg" src={boardImg} alt="board" draggable="false"/> { pieces.map(piece => <Piece key={piece.id} piece={piece}/>) } </div> ) }
内容的提问来源于stack exchange,提问作者Danilo Borrelli
相关产品推荐
相关产品推荐

