3
0

More than 1 year has passed since last update.

Django+Reactで学ぶプログラミング基礎(27): Reactチュートリアル(タイムトラベル実装とチュートリアルまとめ)

Last updated at Posted at 2022-06-16
[前回] Django+Reactで学ぶプログラミング基礎(26): Reactチュートリアル(着手履歴表示とKeyプロパティ)

はじめに

前回は、タイムトラベル機能に必要な知識を勉強しました。
今回は、その実装を完成させ、チュートリアルのまとめを行います。

今回の内容

  • タイムトラベル機能を追加
    • タイムトラベルを実装
    • まとめ

タイムトラベルを実装

三目並べゲームの着手履歴を表すリスト項目のkeyを決める

  • すべての着手には、関連付けられた一意なIDが存在
    • 着手順のインデックスを表す連番数字
    • ゲーム中に、着手が削除/挿入/並び替えされることはない
      • よって、着手のインデックスをkeyとして使うのは安全
    • Gameコンポーネントのrenderメソッド内で、keyを追加
      • <li key={move}>
src/index.js
    const moves = history.map((step, move) => {
      const desc = move ?
        'Go to move #' + move :
        'Go to game start';
      return (
        <li key={move}>
          <button onClick={() => this.jumpTo(move)}>{desc}</button>
        </li>
      );
    });

image.png

  • VS Codeで、アプリをデバッグ起動(F5)
    • ブラウザでデベロッパーツール(F12)のコンソールを確認
      • Reactのkeyに関する警告が表示されなくなった
        image.png

リスト項目内のボタンクリックによりコールされるjumpToメソッドを実装

  • まず、Gameコンポーネントのstateに、いま何手目の状態を見ているかを表すstepNumberプロパティを追加
    • Gameconstructor内で、stateの初期値としてstepNumber: 0を追加
src/index.js
class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      history: [{
        squares: Array(9).fill(null),
      }],
      stepNumber: 0,
      xIsNext: true,
    };
  }
  • 次に、Game内にjumpToメソッドを定義
    • stepNumberを更新する
    • stepNumberの値が偶数の場合、xIsNexttrueに設定
      • 偶数かの判断に、厳密等価演算子(===)を使用
        • オペランド比較時、型変換(キャスト)しない
        • 二つのオペランドの型が異なる場合、常に異なるものと判断
    • setStatestatehistoryプロパティは指定しなくてよい(変更不要のため)
      • 理由は、stateの更新はマージされるため
        • ReactはsetStateで指定されたプロパティは更新、未指定のプロパティはstateにそのまま残す
src/index.js
  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: (step % 2) === 0,
    });
  }

image.png

マス目をクリックしたときに実行されるGameコンポーネントのhandleClickメソッドを変更

  • statestepNumberプロパティは、現在ユーザに見せている着手を表す
    • 新しい着手が発生した場合、this.setStateの引数にstepNumber: history.lengthを加え、stepNumberを更新
  • 時間を巻き戻し過去の着手に戻った場合、それより新しい着手履歴を捨て去る
    • this.state.historyを読み取る処理を、this.state.history.slice(0, this.state.stepNumber + 1)に書き換える
src/index.js
  handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    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
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }
  • 最後に、常に最後の着手後状態をレンダリングするのではなく、stepNumberによって現在選択されている着手をレンダリング
    • ゲーム履歴内のいずれの手番をクリックしても、盤面は該当着手が発生した直後の状態を表示するようになる
    • Gameコンポーネントのrenderを書き換える
src/index.js
  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);

image.png

  • ブラウザで更新されたアプリを確認
    • 5手目までプレイ
      image.png
    • Go to move #2をクリック
      • 盤面が2手目直後の状態表示に切り替わる
        image.png

まとめ

おめでとうございます! 三目並べゲーム完成です。

チュートリアルで学んだ概念

  • React要素
  • Reactコンポーネント
  • Props
  • State
  • State VS. Props
    • 共通点
      • Reactコンポーネントの以下操作で使用される
        • データの受け渡し
        • ハンドリング
        • 画面表示
    • 違い
      • State: コンポーネントが持っている状態
      • Props: 親コンポーネントから渡されたプロパティ
    • 使い分け
      • コンポーネント内部状態の操作にはStateを使用
      • 直接外部コンポーネントのStateに接続する場合は、Propsで受け渡す

ゲーム機能のまとめ

  • 三目並べが遊べる
  • 決着がついたときに表示できる
  • ゲーム進行にあわせ履歴が保存される
  • 着手履歴の見直しや盤面の過去状態を参照できる

改良アイディアにチャレンジ

  • 履歴内の着手の位置を(col, row)というフォーマットで表示
  • 着手履歴のリスト中で現在選択されているアイテムを太字にする
  • Boardでマス目を並べる部分を、ハードコーディングでなく、2つのループを使用するように書き換える
  • 着手履歴のリストを昇順/降順いずれでも並べかえられるよう、トグルボタン(toggle button)を追加
  • どちらかが勝利した際に、勝利につながった3つのマス目をハイライト
  • どちらも勝利しなかった場合、引き分けメッセージを表示

おわりに

チュートリアルを通じて、Reactの基本を勉強しました。
次回も続きます。お楽しみに。

[次回] Django+Reactで学ぶプログラミング基礎(28): Reduxチュートリアル(準備と概要)
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0