Reactを初めて触ってみました(tutorialその⑦)
このページはReact公式ページのtutorialを体験したメモと初心者なりの解釈を記述したページになります。
前回までは基本となるゲームの作りまで完成しました。ここからは履歴の機能に取り掛かっていきます。
※WEB翻訳をそのまま載せているところもありますが自分で理解できるように記事にしています。
歴史の保存
ボードの古い状態に戻って、以前の動きの後にどのように見えるかを見ることができるようにしましょう。
移動が行われるたびに、すでに新しい四角形配列が作成されています。
これは、過去のボード状態を同時に簡単に保存できることを意味します。
このようなオブジェクトをstateに格納しようとしましょう
history = [
{
squares: [
null, null, null,
null, null, null,
null, null, null,
]
},
{
squares: [
null, null, null,
null, 'X', null,
null, null, null,
]
},
// ...
]
トップレベルのゲームコンポーネントが移動リストの表示を担当するようにします。
それで、スクエアからボードに前の状態を引き上げたように、BoardからGameに再びプルアップしましょう。トップレベルで必要なすべての情報を得ることができます。
四角形のクリック操作でBoardの値を変更したようにBoardからGameへ値を渡しましょうってところでしょうか。
最初に、コンストラクタを追加してGameの初期状態を設定します。
class Game extends React.Component {
constructor(props) {
super(props);
this.state = {
history: [{
squares: Array(9).fill(null),
}],
xIsNext: true,
};
}
・・・・・・
ボードを変更して、小道具(props)を介して四角形を取り、Squareが以前に行った変形のように、Gameによって指定された独自のonClick小道具を持っています。
各四角の位置をクリックハンドラに渡すことができるので、クリックされた四角形はまだわかります。
必要な手順の一覧は次のとおりです。
ボードでコンストラクタを削除します。
ボードのrenderSquareでthis.state.squares[i]をthis.props.squares[i]に置き換えます。
ボードのrenderSquareでthis.handleClick(i)をthis.props.onClick(i)に置き換えます。
ボード全体のコンポーネントは次のようになります。
class Board extends React.Component {
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (
<Square
value={this.props.squares[i]}
onClick={() => this.props.onClick(i)}
/>
);
}
render() {
const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
status = 'Winner: ' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
ゲームのレンダリングでは、最新の履歴エントリが表示され、ゲームステータスの計算を引き継ぐことができます。
render() {
const history = this.state.history;
const current = history[history.length - 1];
const winner = calculateWinner(current.squares);
let status;
if (winner) {
status = 'Winner: ' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div className="game">
<div className="game-board">
<Board
squares={current.squares}
onClick={(i) => this.handleClick(i)}
/>
</div>
<div className="game-info">
<div>{status}</div>
<ol>{/* TODO */}</ol>
</div>
</div>
);
}
ゲームがステータスをレンダリングしているので、ボードのレンダリング機能からステータスを計算する<div className = "status"> {status} </ div>とコードを削除できます。
次に、handleClickメソッド実装をBoardからGameに移す必要があります。
Boardクラスから切り取り、Gameクラスに貼り付けることができます。
ゲームの状態は構造が異なるため、少し変更する必要があります。
GameのhandleClickは、新しい履歴項目を連結して新しい履歴配列を作成することによって、新しい項目をスタックにプッシュすることができます。
handleClick(i) {
const history = this.state.history;
const current = history[history.length - 1];
const squares = current.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
history: history.concat([{
squares: squares,
}]),
xIsNext: !this.state.xIsNext,
});
}
この時点で、BoardはrenderSquareとrenderだけを必要とします。 状態の初期化とクリックハンドラは両方ともゲームに存在する必要があります。
翻訳とちょこっと自分的な説明を加えましたがonClickの部分がちょっと理科できないでいました。調べると理解出来なのでメモしておきます。
BoardのrenderSquareでSquareのonClickが以下になるとどうなるか
onClick={() => this.props.onClick(i)}
ちょっとはじめはコードを読んでいてもちゃんと理解はできていなかったのですがドキュメントとネットをみて理解しました。
まずはpropsの概念を理解していませんでした。
ドキュメント
Components and Props
javascript関数で引数として渡すこともできて
ES6クラスを使用してコンポーネントを定義してthis.props.nameを利用できるようです。
ここもわかりやすく参考になりました。
React.jsのProp
つまりはGameでレンダリングするようにした
<Board
squares={current.squares}
onClick={(i) => this.handleClick(i)}
/>
こうなっていることで四角形をクリックしたらBoardの属性のonClickが実行されるんですね。そうして this.handleClick(i) が実行される。
でどの番号の四角形がクリックされたのかをもらい状態を変化しGameのstateで保存する。
はじめは複雑になったのではと思いましたが
見た目上の動作は変わりませんが状態をGameコンポーネントで管理して機能としてはわかりやすく全体的なプロパティの操作もしやすくなったというように見えます。
今回はここまでにしておきます。
←Reactを初めて触ってみました(tutorialその⑥)
→Reactを初めて触ってみました(tutorialその⑧)
コメント
コメントを投稿