3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Reactのチュートリアルをやってみた②

Last updated at Posted at 2022-02-24

はじめに

  • Reactを使って画面作成をしてみたいと思うようになり、サイトを調べてチュートリアル を試しにやってみました。
  • ここにかかれていることをサイト内にあるスターターコード を使って試したものになります。
    • ○×ゲームを作ることが題材となっています。
  • スターターコードにチュートリアルの内容に従いコードを書いていくことで動きを確認することはできました。
  • Reactのチュートリアルをやってみた① に投稿させていただいた第2弾になります。
    • 前回は、Propsstateについて、理解した内容をイメージにしてみました。
  • 今回は、ゲーム完成までのコーディングを行うまでに学んだ以下の内容について纏めてみたいと思います。
    • State のリフトアップ(親:Boardが子:Squareをコントロールできるようにする)
    • 関数コンポーネント
    • 番手の処理
    • 勝ち負けの判定

前回のおさらい

  • Propsは、子のコンポーネントに対して引数を受け渡すのに利用される
  • stateは、自コンポーネント内で情報を保持し記憶しておくことができる
  • 前回は、SquareとBoardのコンポーネントを準備し、Squareでイベントを検知して、情報を記憶しておき、Boardを再描画することで、Squareで記憶した値を表示できることを理解しました。イメージにするとこんな感じだと理解しました。
            

今回理解したこと

Stateのリフトアップ

今、行っているチュートリアルでは○×ゲームを完成させることにありますので、Squareコンポーネントで記憶している内容をBoardコンポーネントで収集し、盤面の内容から勝ち負けを判定できるようにする必要があります。
そのため、以下のイメージにあるようなことをできるようにする必要があります。
        image.png

そのためには、以下のイメージのように、親のコンポーネントでstateを宣言して、Propsを使って子のコンポーネントに情報を展開することで、親コンポーネントで情報を管理し、子コンポーネント間も親を通して情報のやり取りをできるようにすることでStateのリフトアップを行います。
        

チュートリアルの○×ゲームでは、クリックのイベントも親コンポーネントで定義し、子コンポーネントの振る舞いを決めます。子コンポーネントは、クリックイベントが発生したら親コンポーネントが定義したイベントに従うようにしています。
コンポーネントのイメージと処理の流れをイメージしてみると、このような感じになると理解しました。
     

関数コンポーネント

Reactでは、rendaerメソッドだけを有して、stateを持たないコンポーネントは、React.componentを継承する代わりに、Propsを引数として受け取り、表示すべき内容だけを返す(return)できるように関数としてていぎすることができる。
クラスコンポーネントとして書くより、関数コンポーネントはコーディングが楽になる。
実際、stateのリフトアップした結果を見てみると、実際にやっていることは、renderメソッドだけになっています。
     

番手の処理

番手の処理、つまり”○” と ”×” の攻め手の切り替えが👆の処理までだと実現できていないので、実現しましょう!という話になります。
ここは、stateで真偽(True/False)を記憶して、その評価の結果によって、”○”と”×”を切り替えられるようにしていくことで実現できます。

  • Boardコンポーネントのstateに変数:xIsNexttrueを初期地として追加
  • イベントが発生するたびに真偽の変更と、"○"と"×"の切り替えができるようにhandleClick関数に処理を追加
    • squares[i]に変数:xIsNextの真偽によって、"○" か"×"をセット
    • setStateメソッドで、squares[i]state.squaresに、変数:xIsNextに変数:xIsNextではない値をstateの情報として記憶する
  • Boardコンポーネントのレンダー内にconstで定義されている今、どっちの番かを表示するstatusにも変数:xIsNextの真偽によって、"○" か"×"を切り替えができるように書き換える

勝ち負けの判定

勝ち負けの判定をするためのcomponentなどの描画などが目的の関数コンポートンとは異なるヘルパー関数を用意するとあった。
ここでは、処理のイメージ化して書いてきたけど、純粋にロジックなのでコードベースで理解をした。
コードは以下のようにfunctionで関数であることを宣言して、関数名(引数)としてreturnで処理結果を返している。

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

一方の呼び出し側のBoardコンポートでは、以下のように書き換えることで、勝ち負けの判定の結果に基づき、constで定義していたstatuslet(再代入可能な変数に定義しなおしている)のstatusに対して、ゲームが続行で、手番がどっちか、もしくは決着がついて、Winnerが誰になったのか、文字列を再代入する形で表現できるようにしている。

  render() {
    const winner = calculateWinner(this.state.squares);
    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

まとめ

準備するコンポーネントが 'state' を定義し情報を記憶させておくべきコンポーネントか否かでコンポーネントクラスで定義するのか、関数コンポーネントとして定義するのかを整理しながら、まずは動かすためにコンポーネントクラスで定義したとしても、やりたいことを整理していく中で リファクタリング しながら実装することがポイントになると理解した。

3
1
1

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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?