2020-08-13

React Hooksを使うと何が嬉しいのか

触れられていなかったReact Hooksが気になっていたので、少し勉強してみました。

後から気がついたのですが、職場で開発しているプロダクトのコードでは既にReact Hooksを使っていました。楽しそうです。

関数コンポーネントでステートと副作用を扱える

useState

Reactではコンポーネントを組み合わせるようにしてページを実装します。コンポーネントはレンダーのサイクルを跨るステートを持つことができます。コンポーネントを関数で書くこともできますが、この関数コンポーネントはステートを扱えませんでした。そのために小さなコンポーネントでもクラスで書かなければならないのは面倒でした。

フックを使うと関数コンポーネントでもステートを扱えるようになります。副作用としてレンダーのサイクルに干渉できるようにもなります。つまりクラスでできることと同等のことができるようになるのですね。

ある関心事を凝集した定義にできる

useEffect

クラスには副作用を記述するためのメソッドが用意されています。componentDidMountcomponentWillUnmountなどです。たとえば購読の開始とそのクリーンアップをそれぞれのメソッドに書きます。

ここで問題があります。componentDidMountcomponentWillUnmountそれぞれのメソッドに書くわけなので、ある関心事についてのコードが分散してしまします。購読の開始とクリーンアップの手続きをひとつのファイルに書くことはできますが、その呼び出しをcomponentDidMountcomponentWillUnmountに書く必要があります。

また、ステートは.stateプロパティに持つので、複数の関心事が混ざります。なのでsetStateはマージしてステートを更新するわけです。

フックを使うとある関心事をより凝集した定義にできます。たとえば購読の開始とそのクリーンアップはuseEffectで一度に定義できます。ステートはuseStateの戻り値で得られるので.stateプロパティに囚われなくなります。ここで、フックはある関心事をレンダーのサイクルに結びつけるものと理解できます。

クラスではある関心事をサイクルの中に自分で結びつけていかなければなりません。ステートにしても副作用にしてもある関心事をクラスにねじ込むような感じがしますね。

カスタムフックが美しい

Custom hook

フックは関数のトップレベルに書くルールがあります。これは実行の順番が保たれる必要があるためのようです。たとえばif文などを使って条件つきでフックを呼び出してはいけません。それが守られれば一連の定義をカスタムフックとしてひとつの関数に切り出せます。

これが非常に強力です。クラスでは.statecomponentDidMountに定義や呼び出しを分散せざるを得なかったものが、ひとつのカスタムフック(関数)の呼び出しで済ませられるようになります。ステートや副作用に関するロジックを再利用しやすくなるわけです。

ある関心事を抽出したものがカスタムフックと言えそうです。フックの仕組みがそのような切り出しを可能にしていますが、またそれ自体がフックであるとするのにある種の芸術美を感じすね。公式にも次のような説明があります。

カスタムフックはReactの機能というよりは、フックの設計から自然と導かれる慣習のようなものです。


フックは関数コンポーネントでもステートや副作用を扱えるようにするものです。クラスに比べて、ステートや副作用を関心事に基づいて書くことができます。フックがレンダーのサイクルと関心事を結びつける役割を担うからです。またその記述をカスタムフックに抽出できることが最大のポイントだと思います。公式のFAQでも「カスタムフックに抽出」と何度も言及があります。

関心の分離高凝集/疎結合はプログラミングの重要なパラダイムだと思っています。フックをそのための仕組みだと捉えるとコードをよりエレガントなものにできる気がしてきますね。

福地春喜
フリーランスのソフトウェアエンジニア
情報資源管理としてのデータベース・コンテンツ設計に関心があります。数学や哲学、認知言語学など対象の捉え方に係る考え方に興味があります。システム開発の傍ら、それを推進するチームの体制やプロセス・仕組みづくりの支援もしています。 もっと詳しく