2020-10-02

Reactチュートリアルを弄って遊ぶ Hooks編

引き続きReactチュートリアルで遊んでいく
今回はReact Hooksを使ってクラスコンポーネントを関数コンポーネントにリファクタリングしていく
現在の状態はこんな感じ

対象となる箇所

Square コンポーネントは既に関数コンポーネントになっているのでやることはない
Board コンポーネントはクラスコンポーネントだけど、 state を持っていないのですぐ関数コンポーネント化することができる
Game コンポーネントは state を持つクラスコンポーネントなので、こいつが今回のメインターゲットとなる

Boardコンポーネントの関数コンポーネント化

リファクタ前のBoardコンポーネントはこんな感じ

見ての通り state を持っていない

  1. 関数コンポーネントは関数としてExportするので、 export const Board = (props) => {〜} となる
  2. 関数コンポーネントは render() を用意する必要はなく、そのコンポーネントで表示すべき内容を return するだけでOK
  3. 親コンポーネントから受け取ったパラメータは this.props ではなく、関数の引数として受け取る形になるので、 props.XXX という感じで this はなくなる

といった感じで、 state がなければ超簡単に関数コンポーネント化ができる
(変換したときのコミットはこちら)

Gameコンポーネントの関数コンポーネント化

リファクタ前のGameコンポーネントはこんな感じ

こいつは state を持っているので、Hooksを使ってリファクタする必要がある
useState を使う方法と、 useReducer を使う方法があるが、ここでは useState を使った方法で行う

  1. 基本的な関数コンポーネント化に必要な作業は Board コンポーネントの時と同じ↑
  2. constructor で定義されている this.state に着目し、同じ状態を管理できるよう必要な分だけ useState を使用する(今回は全てのstateを別々に管理するようにしたが、1つのオブジェクトでもOK)
  3. this.state でstateを参照していた箇所を、 useState の戻り値のstate変数で置き換える
  4. this.setState でstateの更新をしていた箇所を、 useState の戻り値のstate更新関数で置き換える

Board コンポーネントの時と比べたら、当然 state がある分ちょっと面倒なところはあるが、上記ポイントを押さえればそこまでハマりどころはないはず
(変換したときのコミットはこちら)

useReducerを使ったGameコンポーネントのリファクタ

リファクタ前のuseStateで書かれたGameコンポーネントはこんな感じ

Reduxでも名前はおなじみの useReducer を使った場合のリファクタをやってみる
useStateuseReducer もコンポーネントの中だけで状態が完結するという点では同じだが違いもある

どちらを使うべきなのかは、公式のuseReducerに説明があるので、自分のアプリではどうなのかを考えるとよい
(けどまぁReducerで書いておくのが無難な気がする)

なお、Reduxはグローバルに状態管理を行うので、コンポーネントを横断するようなステートを管理する場合に導入を検討するとよい

  1. 初期ステータスを1つのオブジェクトで用意する
  2. useReducer を使って現在のstateと、それを更新するための dispatch を作成する
  3. useState の変数と更新関数を useReducer で作成した statedispatch で置き換える

(変換したときのコミットはこちら)

ここまでのコードはこんな感じ
最初の状態と比べたらまぁまぁきれいになって、ある程度現場感が出たのではなかろうか