React初学者指南:时间旅行(1)
首先
我希望通过多次的文章来使用 React 开发一个井字游戏(三连棋),既作为自己的复习,也作为备忘录的意思。
-
- React
-
- CodeSandbox(公式)
- CodeSandbox(非公式)
系列项目列表
-
- React入门1:环境搭建[在线版]
-
- React入门1.5:环境搭建[本地版-番外篇]
-
- React入门2:盘面的创建
-
- React入门3:交互实现
-
- React入门4:重构[提升版]
-
- React入门5:重构[交互版]
-
- React入门6:实现回合
-
- React入门7:游戏胜利判定
-
- React入门8:实现文本
-
- React入门9:时光旅行(1)(本期)
-
- React入门10:时光旅行(2)
- React入门11:时光旅行(3)
关于目的
整体目标
我们将在React公式教程中实现一个3×3格子的井字棋游戏。
这次的目标
在之前的文章中,我们完成了游戏系统。从这篇文章开始,我们将实现可以回到过去的回合的时间旅行功能。本次准备工作是设计一个新组件,用于记住过去棋盘的状态。
时间旅行 (1)
您可以在下一页上查看上次的源文件。
- 前回の内容はコチラから!
保留之前的回合方法
目前,井字遊戲由Board組件和Square組件組成。
Board コンポーネント
盤面を表示する
state 型の squares 配列で盤面の状況を管理する
Square コンポーネントがクリックされたときのイベントとして handleClick() 関数を定義している
Square コンポーネント
盤面上にある1つのマスを表示する
因此,我们将创建一个名为Game的组件,用于保存每个移动后棋盘的状态。在这个组件中,我们会将Board组件的状态和数组提升。
编码
我們將在App.js中的Board組件進行如下更改:
-
- メインコンポーネントとしての定義をやめる
state 型の変数と配列の宣言を省く
次のプロパティを設定する
xIsNext : 現在の手番
squares : 現在の盤面の状況
onPlay : 盤面の状況を記憶する処理と手番を交代する処理を行う関数
handleClick() 関数の変更
state 型の変数と配列の更新処理を省く
onPlay プロパティで受け取った関数を実行する
更新された盤面の状況を渡す
function Board({ xIsNext, squares, onPlay }) {
const winner = calculateWinner(squares);
let status;
if (winner) {
status = "勝者: " + winner;
} else {
status = "プレイヤー: " + (xIsNext ? "X" : "O");
}
function handleClick(i) {
if (squares[i]) {
return;
}
const nextSquares = squares.slice();
if (xIsNext) {
nextSquares[i] = "X";
} else {
nextSquares[i] = "O";
}
onPlay(nextSquares);
}
return (
<>
<div>{status}</div>
<div className="board-row">
<Square value={squares[0]} onSquareClick={() => handleClick(0)} />
<Square value={squares[1]} onSquareClick={() => handleClick(1)} />
<Square value={squares[2]} onSquareClick={() => handleClick(2)} />
</div>
<div className="board-row">
<Square value={squares[3]} onSquareClick={() => handleClick(3)} />
<Square value={squares[4]} onSquareClick={() => handleClick(4)} />
<Square value={squares[5]} onSquareClick={() => handleClick(5)} />
</div>
<div className="board-row">
<Square value={squares[6]} onSquareClick={() => handleClick(6)} />
<Square value={squares[7]} onSquareClick={() => handleClick(7)} />
<Square value={squares[8]} onSquareClick={() => handleClick(8)} />
</div>
</>
);
}
接下来,我们将定义 Game 组件如下。
-
- これをメインコンポーネントとする
Board コンポーネントのリフトアップする
state 型の history 配列を定義する
盤面の状況を示す
初期値: [Array(9).fill(null)]
set関数名: setHistory
state 型の xIsNext 変数を定義する
現在の着手を示す
初期値: true
set関数名: setXIsNext
currentSquares 変数を定義する
現在の盤面の状況を示す
初期値: 最新の盤面の状況
handlePlay() 関数の定義
盤面の状況を記憶する
手番を交代する
Board コンポーネントをレンダーする
各プロパティに適切な値または関数を渡す
export default function Game() {
const [history, setHistory] = useState([Array(9).fill(null)]);
const [xIsNext, setXIsNext] = useState(true);
const currentSquares = history[history.length - 1];
function handlePlay(nextSquares) {
setHistory([...history, nextSquares]);
setXIsNext(!xIsNext);
}
return (
<Board xIsNext={xIsNext} squares={currentSquares} onPlay={handlePlay} />
);
}
接下来会展示执行结果。由于进行了升级,组件的构成发生了变化,但操作内容与上次相同。
通过这样,游戏组件中的state类型的history数组可以记录游戏界面的情况。history数组的元素表示某个回合的游戏界面情况。具体来说,history[i]表示第i次回合的游戏界面情况,history[i][0]表示游戏界面左上角格子的状态。
最后
在这次实现时间旅行功能的过程中,我们进行了对Game组件进行定义和提升。请参考下一页的当前阶段源代码。
下一步,我们将在Game组件中添加文本,以便能够回到过去的回合。