何故僕たちは React のコンポーネントを分割するのか

scope🌐
created at
links
[...]
histories
[...]

この記事ははてなエンジニア Advent Calendar 2023の15日目の記事です。

皆さんは React 書いてますか、最近のフロントエンドを触った人なら書いた事がない人は居ないと思います。

React を書いていてよく起きる問題に、コンポーネントをどれぐらいの粒度で分割するか、という事があると思います。 ただし、多くの皆さんはアトミックデザインでパターンを適用して分割!で済ませていませんか?

現代の React ではただコンポーネントを分割すれば良いだけではない状態になっています。 というのも、React のコンポーネントを分割するというのは、そのコンポーネントの挙動すら変え得る行為なのです。

見通しのための分割

よくある分割の理由として、コードの見通しを良くする為の分割があります。 コンポーネントがあまりにも肥大化すると、行数が増えて単純に見通しが悪くなってしまうので、それを対処するための分割です。

この時の分割の単位は人それぞれで、これといった決まった型はないと思います。

再利用のための分割

これもよくある理由ですね。ボタンや各種入力欄など、アプリケーションの色々な箇所で使うためにコンポーネントを分割するというパターンです。

アトミックデザインなど、デザインパターンを当て嵌めることが多いですね。

再レンダリングを防ぐための分割

ここからがコンポーネントの挙動に関わる分割です。

React のコンポーネントは以下の3つのタイミングで再レンダリングされます。

  • 自身の state が更新された時
  • 自身の props が更新された時
  • 親のコンポーネントが再レンダリングされた時

もし、ページを1つのコンポーネントで作った場合、1つの state が更新されただけでページの全てが再レンダリングされてしまいます。 そのため、適切な粒度でコンポーネントを分割する事で、再レンダリングの影響を必要な要素のみに抑えることができます。

Error boundary のための分割

Error boundary は自身と子のコンポーネントで起きたエラーをキャッチし、代わりのコンポーネントを描画する機能です。 これによって、コンポーネントのレンダリング中にエラーが発生しても、UI の崩壊する範囲を最小限に抑える事ができます。 Error boundary についての詳細は ReactのErrorBoundaryで内部のエラーをキャッチする が分かりやすいです。

もし、コンポーネントが分割されていなかった場合、多くの UI 要素が非表示になってしまいます。

Suspense のための分割

Suspense は React 18 で stable になった機能です。

Suspense は子のコンポーネントの1つ以上がサスペンドしている時に代わりのコンポーネントを描画してくれるコンポーネントです。 今まで loading で出し分けをしたりと各自で実装していた読み込み中の表現を、React の機能を使ってよりスマートに表現できるようになりました。

Suspense については ReactのSuspense対応非同期処理を手書きするハンズオン をオススメします。

こちらもコンポーネントを適切に分割することで、fallback される UI 要素を最小限に抑えられます。

React Server Components のための分割

React Server Components は React のコンポーネントをブラウザだけではなくサーバー側でもレンダリングする仕組みです。 また、ブラウザからサーバー側の関数を呼び出す事も可能です。

SSR との大きな違いは、全てのコンポーネントをレンダリングする訳ではないという点です。 SSR では基本的に全てのコンポーネントが描画されていましたが、RSC では一部のコンポーネントはサーバー側で描画されません。

RSC におけるコンポーネントの分割はとても重要です。 というのも、サーバーでのみ描画できるコンポーネントとブラウザでのみ描画できるコンポーネントが生まれるからです。 サーバー側で描画されるコンポーネントでは useState などのフックは利用できません。 逆にブラウザで描画されるコンポーネントではサーバー側の関数を呼び出せません。 そのため、RSC におけるコンポーネントの分割は必然的にしなければいけなくなる行為でもあります。

React Server Components については 一言で理解するReact Server Components の記事を読むと良いでしょう。

おわりに

こうやって書き出してみると、分割の理由は沢山ありますね 普段からこの数の観点をもとに React コンポーネントを分割するのはかなり難しいと思います。 もしコンポーネントを分割する、または新しく実装する時は、是非この記事を参考にしてみてください。