Open10

ReactのカスタムHooksに関するディレクトリ戦略メモ

りゅーそうりゅーそう

React Hooksとはなんなのか?

先ほどのドキュメントより

フックを使えば、ステートを持ったロジックを、コンポーネントの階層構造を変えることなしに再利用できるのです。

関連する機能(例えばデータの購読や取得)をライフサイクルメソッドによって無理矢理分割する代わりに、フックは関連する機能に基づいて、1 つのコンポーネントを複数の小さな関数に分割することを可能にします。

りゅーそうりゅーそう

以下の記事がとても分かりやすい。
「React Hooksとカスタムフックが実現する世界 - ロジックの分離と再利用性の向上」
https://qiita.com/sonatard/items/617f324228f75b9c802f

「useCallbackはとにかく使え! 特にカスタムフックでは」
https://blog.uhy.ooo/entry/2021-02-23/usecallback-custom-hooks/

カスタムフックを作る理由は、普通の関数を作る理由と全く同じであり、すなわち責務の分離とかカプセル化です。

カスタムフックは再利用性のために作られるものなので、より高い再利用性のためにはuseCallbackが必要です。

りゅーそうりゅーそう

Hooksに限った話ではないが、以下のディレクトリ構成はとても参考になる。
「SPA Componentの推しディレクトリ構成について語る」
https://zenn.dev/yoshiko/articles/99f8047555f700#hooksの抜き出し

自分の中のcustom hooksを作るタイミングとして「複数のComponentで共有したいような汎用的な処理」が出てきたときに src/hooks に汎用hooksとして切り出す、という形をとっていました。
ただ、このルールだと「他のComponentとかぶる処理はないけどロジックが多めなComponent」の内部ロジックがどんどん膨らんできてしまうんですよね。

わかる.... hooks ディレクトリに処理をまとめることで、「再利用」しやすくなる一方でHooksを作成するハードルが上がってコンポーネントが膨れてしまう...カジュアルに使いたい。

りゅーそうりゅーそう

どうすればよさそう?

hooks ディレクトリは再利用というHooksの役割を果たしてくれているのであると良い
コンポーネントディレクトリに useComponent.hook.ts みたいなファイルを作ってカジュアルに処理をHooks化していくのはどうか?
以下のようなイメージ

Component
 - component.tsx
 - component.stories.tsx
 - useComponent.hooks.ts

(必要があればContainerコンポーネントみたいなものも作る?)

何が嬉しいか?

  • コンポーネントにフックが増えてきたときにカスタムフックを作るみたいな習慣がチームに生まれる。
  • テストがしやすくなる
    • 具体的には受け取るStateをmockなどして、テストケースがかける
      https://github.com/testing-library/react-hooks-testing-library
    • storybookなどでコンポーネントを管理できる
    • 要はテスト・storybookの対象のコンポーネントからHooksをなくしたいというモチベーション

UI部分のテストやstorybook管理をするならコンテナ・プレゼンテーションパターンも併用する
https://zenn.dev/morinokami/books/learning-patterns-1/viewer/presentational-container-pattern

要はコンテナ・プレゼンテーションパターンをカスタムHooksでカジュアルにやろうという感じ

辛みは?

  • 同じようなHooksが作られてしまう可能性(管理しにくいのでは?)
  • hooks ディレクトリとの棲み分けわかりづらい
りゅーそうりゅーそう

同じようなHooksが作られてしまう可能性

個人的には同じようなHooksがあっても問題ないと考える。気付いたらリファクタしてまとめれば良い。上のパターンで作られるカスタムHooksは「再利用」されることはほぼないと考える。

りゅーそうりゅーそう

hooks ディレクトリとの棲み分けわかりづらい

これは仕組み化しないといけなさそう。

パッと思いついたのは、React Query/SWR/Recoilなど最近のライブラリではグルーバルにキーで状態(キャッシュ)を管理するものがあるので、そのライブラリを使用したカスタムHooksは hooks ディレクトリにおくとかにすると事故が減りそう(キャッシュキーごとにフォルダ管理するのも合わせると良い。以下の記事も参考になる)
https://zenn.dev/yoshiko/articles/607ec0c9b0408d#recoilを使ったglobal-stateの管理

その他のカスタムHookについては××回利用されているかとかで適宜まとめるとか?無理に共通化しなくても良い気がしている。