React Hooksはステートの管理と副作用のある処理を関心事ごとに整理する
React Hooksは関数コンポーネントでステートの管理と副作用のある処理を扱えるようにするものです。この記事では、クラスコンポーネントと比較してフックがどのように関心の分離や高凝集・疎結合に寄与するかを考えてみます。
関数コンポーネントでステートの管理と副作用のある処理を扱う
Reactではコンポーネントを組み合わせてページを実装します。各コンポーネントはレンダーのサイクルをまたがるステートを持てます。コンポーネントを関数で実装することもできますが、関数コンポーネントはステートを持てませんでした。小さなコンポーネントでもステートを持つにはクラスコンポーネントにしなければならないのは面倒でした。
フックは関数コンポーネントでもステートの管理を扱えるようにします。副作用のある処理をレンダーのサイクルに組み込めるようにもなります。かくして関数コンポーネントでもクラスコンポーネントと同じことができるようになりました。
ステートの管理と副作用のある処理を関心事ごとに整理する
クラスコンポーネントにはレンダーのサイクルに応じたメソッドcomponentDidMount
やcomponentWillUnmount
などが用意されています。副作用のある処理を実装するためのメソッドです。たとえばデータの購読の開始とそのクリーンアップをこれらのメソッドに実装します。
ここで問題があります。データの購読の開始とクリーンアップの手続きをcomponentDidMount
やcomponentWillUnmount
に分けて実装する必要があり、ひとつの関心事に対応するコードが分散してしまいます。また、ステートはクラスのプロパティ.state
に持つので、複数の関心事が混在してしまいます。
フックを利用するとステートの管理と副作用のある処理を関心事ごとに整理できます。たとえばデータの購読の開始とそのクリーンアップはuseEffect
で一度に定義できます。ステートはuseState
の戻り値で得られるのでプロパティ.state
に囚われなくなります。フックは関心事の定義をレンダーのサイクルに結びつけると捉えると実装を整理しやすくなります。
カスタムフックでロジックをひとつの関数に抽出する
フックは関数の先頭に記述するルールがあります。これはレンダーのサイクルにおいて実行の順番が保たれる必要があるためのようです。たとえばif
文などの条件つきでフックを呼び出してはいけません。それが守られれば一連の実装をカスタムフックとしてひとつの関数に切り出せます。
これが非常に強力です。クラスコンポーネントではcomponentDidMount
や.state
に実装を分散せざるを得なかったものが、ひとつのカスタムフック(関数)の呼び出しにできるからです。ステートの管理や副作用のある処理を再利用しやすくなるわけです。
カスタムフックはある関心事についてのロジックを抽出したものと言えます。フックの仕組みがそのような切り出しを可能にしていますが、カスタムフックそれ自体がまたフックであるとできることに構造美のようなものを感じます。公式にも次のような説明があります。
カスタムフックはReactの機能というよりは、フックの設計から自然と導かれる慣習のようなものです。
まとめ
フックは関数コンポーネントでもステートの管理や副作用のある処理を扱えるようにします。クラスコンポーネントに比べて、ロジックを関心事ごとに整理できます。さらにその実装をカスタムフックに抽出できることが最大のポイントです。公式のFAQでも「カスタムフックに抽出」と何度も言及があります。
関心の分離や高凝集・疎結合はプログラミングの重要な原則です。フックはそのための仕組みであると捉えるとコードをよりスマートにできます。
Discussion