我一直在编写一个chess应用程序,以便帮助自己快速掌握React中引入的钩子。一个用于棋盘本身,另一个用于移动历史记录,它允许您恢复到上一步。当我尝试使用Board组件中的回调将移动传递到移动历史记录时,我得到一个错误Cannot update a component ('App') while rendering a different component ('MoveHistory')
。我理解这个错误,但我不完全确定应该如何处理它。
我的组件(减去所有我确信不相关的部分)如下:
应用程序tsx(父组件)
...
const STARTING_FEN = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'
function App() {
const [FEN, setFEN] = useState(STARTING_FEN);
const [moveHistory, setMoveHistory] = useState<string[]>([]);
const [fenHistory, setFenHistory] = useState<string[]>([]);
// rewind game state to specified move index
function onRewind(target: number) {
setFEN(fenHistory[target]);
setMoveHistory(moveHistory.slice(0, target));
setFenHistory(fenHistory.slice(0, target));
}
// add a new move to the move history
function onMove(move: string, FEN: string) {
setMoveHistory([...moveHistory, move]);
setFenHistory([...fenHistory, FEN]);
}
return (
<div className='app'>
<Board FEN={FEN} onMove={onMove} />
<MoveHistory moves={moveHistory} onRewind={onRewind} />
</div>
);
}
export default App;
Board.tsx(同级组件1)
...
interface BoardProps {
FEN: string;
onMove: Function;
}
function Board(props: BoardProps) {
const splitFEN = props.FEN.split(' ');
const [squares, setSquares] = useState(generateSquares(splitFEN[0]));
const [lastClickedIndex, setLastClickedIndex] = useState(-1);
const [activeColor, setActiveColor] = useState(getActiveColor(splitFEN[1]));
const [castleRights, setCastleRights] = useState(getCastleRights(splitFEN[2]));
const [enPassantTarget, setEnPassantTarget] = useState(getEnPassantTarget(splitFEN[3]));
const [halfMoves, setHalfMoves] = useState(parseInt(splitFEN[4]));
const [fullMoves, setFullMoves] = useState(parseInt(splitFEN[5]));
...
// handle piece movement (called when a user clicks on a square)
function onSquareClicked(index: number) {
... // logic determining where to move the piece
{
props.onMove(moveName, getFEN())
}
}
...
// get the FEN string for the current board
function getFEN(): string {
... //logic converting board state to strings
return `${pieceString} ${activeString} ${castleString} ${enPassantString} ${halfMoves} ${fullMoves}`;
}
return (
<div className='board'>
{[...Array(BOARD_SIZE)].map((e, rank) => {
return (
<div key={rank} className='row'>
{squares.slice(rank * BOARD_SIZE, BOARD_SIZE + rank * BOARD_SIZE).map((square, file) => {
return (
<Square
key={file}
index={coordsToIndex(rank, file)}
pieceColor={square.pieceColor}
pieceType={square.pieceType}
style={square.style}
onClick={onSquareClicked}
/>
);
})}
</div>
)
})};
</div>
);
}
export default Board;
MoveHistory.tsx(同层级元件#2)
...
interface MoveHistoryProps {
moves: string[],
onRewind: Function;
}
function MoveHistory(props: MoveHistoryProps) {
return (
<div className='move-history'>
<div className='header'>
Moves
</div>
<div className='move-list'>
{_.chunk(props.moves, 2).map((movePair: string[], index: number) => {
return (
<div className='move-pair' key={index}>
<span>{`${index + 1}.`}</span>
<span onClick={props.onRewind(index * 2)}>{movePair[0]}</span>
<span onClick={props.onRewind(index * 2 + 1)}>{movePair[1] || ""}</span>
</div>
)
})}
</div>
</div>
)
}
export default MoveHistory;
我已经看了很多其他的stackoverflow问题,它们似乎回答了我在这里提出的问题,但对我来说,我似乎已经在做那里建议的事情了,所以我不确定有什么区别。我也看到了一些使用Redux的建议,我不反对,但如果可以避免的话,那就太好了。
1条答案
按热度按时间iyr7buue1#
问题是你在
MoveHistory
的渲染中调用了props.onRewind
。1.应用程序开始渲染
onRewind
1.在
onRewind
中,您调用了应用程序中的各种useState
setter方法。应用程序尚未完成渲染,但正在调用其状态修改方法。这就是触发错误的原因。我想你的意思是这样的:
请注意,不是调用
props.onRewind
,而是为它提供一个方法,当单击span时,该方法将调用onRewind
。