i-Vinci TechBlog
株式会社i-Vinciの技術ブログ

React入門 第3回 Hooks APIってなんですか?

こんにちは!年始にM1 MacBook Airを購入してウッキウキの藤田です!
今まで使用していた個人PCは、複数のブラウザとエディターを開くと固まる漢気あふれるスペックでした。
Dockerコンテナが「軽量でサクサク動く」という話とか聞くと、違う世界の話だなぁ、と感じて生きていました。
しかし新しいPCでは、Android StudioやXCodeのエミュレーター・シミュレータを立ち上げながら、ブラウザで調べ物をしつつ、Dockerコンテナを複数立ち上げて、エディターも複数開いて、音楽を聴きつつ......のような感じで色々といい感じに出来る様になって作業効率とQOLが上がりました。
PCの性能って大事ですね!

さて、React入門記事の第3回として、Hooks APIについて書いていきたいと思います。

  1. Webpackを使ってみよう
  2. State, Propって何ですか?
  3. Hooks APIって何なんですか?いったい!
  4. Class Component vs. Functional Component 両方の書き方を試してみよう
  5. コンポーネントのライフサイクルって、ちょっと何ですか?え、なに?
  6. Material UIって?ちょっと何がしたいの?
  7. TypeScriptで書いてみよう
  8. Styled Componentで書いてみよう
  9. Redux, Redux-Saga、って何ですか?イヤイヤ、こわっ!
  10. ちょっとアプリを作ってみよう(3~4回程度に回を分けるかもです)

前回までのおさらい

数独アプリを作成しながらState, Propsについて学びました。

  1. コンポーネントの状態をstateとして管理できること
  2. コンポーネントにpropsとしてデータ・関数を渡すことができること

大きく分けて以上2点を確認しました。

Hooks API

今回はHooks APIについて学んでいきます。
Hooks APIは、React 16.8から導入された機能で、Reactのクラスコンポーネントで利用していた多くの機能を関数コンポーネントで利用可能にすることができる機能です。
Reactのクラスコンポーネントの機能を関数コンポーネントで利用可能にする≒接続する(hook into)、みたいなニュアンスがあるようですね。(参考)

Hooks APIの目的については、Reactの公式ドキュメントのこちらで詳細に述べられています。

Hooks APIにはさまざまな種類があるのですが、今回は基本的な次の3つのフックについて学びたいと思います。

  1. Stateフック: Stateのゲッター・セッターを取得する機能
  2. Effectフック: レンダー後に何か行う必要があることをReactに教える機能。APIを叩いて状態を更新するなどの処理が一番イメージしやすいと思います。
  3. Contextフック: propsとは別経路のデータの渡し方

今回作成したもの

ここまで作成しました。
手元で動かして確認するためには、このブランチの最終コミットをプルしてもらうのがいいかなと思います。

前回から少し手を入れて、なんだかそれっぽい画面になってきました。

001

セルへの値の入力は、前回までの実装だとinput要素を利用していたのですが、"", 1~9までの入力なのでselect要素を利用した方がいいかなと思い、その様に変更しました。

002

ダークモードみたいなものも実装しています。

003

後ちょっと細かいですけど、何かしらのロード中とかに表示するスピナーをモーダルとして実装しました。(ローカルだと一瞬でデータが取れるので、スピナーが表示されるのも一瞬です(汗))

(スピナーの動きをどうしても見たい人は、こちらのsetIsFetching(false)をsetIsFetching(true)にして見て下さい)

では、実装の方を見ていきましょう。

実装の確認

Stateフック、Effectフック、Contextフックの順番で実装を確認していきましょう。
主に見るファイルは、App.jsx, SudokuBoard.jsx, MenuButtons.jsx, SudokuCell.jsxの4つで大丈夫かなと思います。

Stateフック

このあたりで使っています。

const [blocks, setBlocks] = useState([]);
const [isFetching, setIsFetching] = useState(true);

Stateフックは、実は前回から使っていました。
useState(initialState)を使用して、初期値がinitialStateのstateのゲッターとセッターを取得できます。

今回の実装ではセッターは、この辺りここら辺で使用しています。

Effectフック

この辺りで使っています。

useEffect(() => {
  setIsFetching(true)
  // 数独ゲームデータ取得
  getSudokuDataService()
    .then(svcResult => {
      const sudokuData = svcResult.data;
      setBlocks(sudokuData);
    })
    .then(() => setIsFetching(false));
}, []);

今回は数独のゲームデータを取得するために、画面が表示された時に1回だけAPIを叩く様な作りにしました。
そのためuseEffectの第2引数に[]空の配列を渡しています。(参考)
これにより、画面が表示された時に初回だけgetSudokuDataServiceを利用してゲームデータを取得する、という動きになります。

Effectフックについては、クリーンアップという機能もあります。
今回は実装しなかったのですが、いずれゲームを開始してからの経過時間などを記録したくなると思います。その時に使うんじゃないかなと思うので、また別の機会に説明できるといいなぁ、という形で今回は進めたいと思います。

Contextフック

この辺りで使っています。

const theme = useContext(ThemeContext);

useContextに引数として渡したThemeContextは、App.jsxで作成してexportしているものです。
今回の実装では、Lightモード/Darkモードの切り替えをThemeContextを利用して行いました。

まず、App.jsxでコンテキストの作成コンテキストに設定するthemeオブジェクトの作成Context.Providerに作成したコンテキストを渡す、などをします。

今回コンテキストで利用するthemeについてなのですが、

  1. propsとして渡して子コンポーネントで使用(該当箇所)
  2. useContextでコンテキストから取得してコンポーネント内で使用(該当箇所)

という形で利用しています。
コンテキストを作成したAppコンポーネント直下の子コンポーネントであれば、propsとして直接渡していいと思います。
SudokuCellコンポーネントのようにコンポーネントツリーの下層にあるコンポーネントにデータを渡す方法として、propsを渡すバケツリレーを関係のないコンポーネントも巻き込んで行うのは少し避けたいところではあります。
そういう時にコンテキストを利用するのがいいのかなぁと思います。

propsのバケツリレーがめんどくさいなぁ、でもコンテキストを使うべきなのかなぁ、と思った時は、こちらが参考になるかもしれません。

まとめ

以上でHooks APIについての簡単な説明を終わります。今回の実装がみなさんの参考になれば嬉しいです。
今回まででなんとなく数独ゲームっぽい画面になってきました。しかしまだ、ゲーム本体の機能は実装されていません。
次回くらいでゲームの本体の機能を実装したいと思います。