足元のReact18
React 18 が2022年の3月に公開された。
Concurrent React がついに実装され、それに伴ってこのバージョンで React Server Components がリリースされる予定。
Hooks 以来のかなり大きな進歩のバージョンになりそう。
色々と影響が大きいが、既に様々な方がReact 18について情報発信されているので、公式をよく読む & ちゃんと調べればある程度は理解できる。
細かい機能の説明はここではスコープ外とし、実際問題足元でReact 18を使うとすると何をどうすればいいのかを今のところの所感と共に書いておく。
多分認識はまた実装してる中で変わっていくと思う。
とりあえずRSCは静観
個人的に一番理解が進んだのがこちら:
まだ公開されていないというのもあるけど、しばらくは本番にがっつり入れるほどにはならないかなという印象。
というか、既にそれなりのコードがある中規模から大規模なReactプロジェクトに途中からこれを入れるのは相当に骨が折れる作業になる...
ので、よほど現状のサービスの技術的ボトルネックを解決してくれることが明確でない限り、する必要がないように見える。
React自体はRSC前提になるわけではなく、RSCは大きな機能の一つ、という立ち位置になると思われるので、今から採用しないとまずい、みたいな温度感ではないという認識。
ただ長い目(数年)で見たときにRSCの機能とかAPIが安定してきてからは「入れられるようにしておく」あるいは「最初から必要な場所で使う」が前提になる気はするので、注意してウォッチしていく必要はあると思っている。
Suspenseは積極的に使っていく
RSCを実際に導入せずとも、Concurrent Reactの恩恵を受けるには基本的にSuspenseを使うことになるし、今後RSCに力を入れていくReactの基礎にSuspenseが含まれることは見えているので、Suspenseに対応したReactにしておくことは今後もReactを使い続けるのであれば今からメリットがあると思う。
そもそもSuspenseは実装方法としてとっても便利。
18からはサーバサイドでも動くようになったってのもある。
上記でリンクさせていただいた記事の中でリンクされている React と Algebraic Effects に関する記事が非常に面白く、Suspense や Hooks の実装の意図が垣間見えるのでぜひご一読を。
SuspenseはReact.lazyだけ?
公式のドキュメントに「Suspenseの現在唯一サポートされている機能はReact.lazyと一緒に使う方法です」みたいに書かれているのだけど、これは少し分かりにくい表現だなあと思った。
「Suspenseが使える場面はReact.lazyを使う場面だけ」っていうように解釈できちゃうような気がするんだけど、実際はそうではない。
Suspenseはあくまでも「Promise を throw する処理を含むコンポーネントをラップしてフォールバックと子要素のレンダリング制御をするコンポーネント」であって、React.lazyのための機能ではないことに注意。
なのでつまりReact.lazyにはSuspenseが必要だけど、SuspenseにはReact.lazyは必要ない。
Suspense with React Query
データフェッチとして React Query を使っている場合、まだExperimentalだけどSuspense対応のデータフェッチが簡単に実装できる。
Experimentalだけど、ReactQueryのSuspenseにおけるAPIのインターフェースが現時点から大きく変わることはない(結局は取得中にPromiseをthrowするということがSuspenseにおいては重要なので)と思われるので、個人的には使用に前のめり。
React Query の React 18 対応、基本的に v4 からとなる。
Please DO NOT expect React Query v3 to work with concurrent features like startTransition, and DO NOT file issues about it.
v3 でも 3.35.0 から peerDependencies に 18 が含まれたが、あくまでもインストールができるだけであって、Concurrent React の機能は v3 では動かない。
となると現時点においては、React 18 を使うならまだ beta な v4 を使うか、もしくは React 17 を使うかになる。
一旦は react-query をしっかり使うのであれば React 18 へのアップグレードは待ちかな。
useTransition の polyfill はちゃんと動くだろうか?
Transition も使うことになる
Suspense を使うなら、 Transition は使う必要が出てくると思う。
処理実行中にフォールバックではなくすでにレンダリング済みのコンポーネントをそのままレンダリングしていて欲しい場合に使用する。
React.startTransition と React.useTransition がある。
一見Function Componentでは後者一択だねみたいな見た目をしているが、ドキュメントを読んだ限り、「Suspenseに対してフォールバックを表示しないことを伝える」という目的でのみ使うなら startTransition の方を使う方がシンプルに書けるように見える。
ちょっとここまだちゃんと実装してないので雰囲気で書いてるけど、useTransitionの返り値の一つであるisPendingを使って明示的にトランジションを取り扱わない限りはそうなんじゃないかなと。
Automatic batching
これはもう自動で実行されるのでよろしく!という感じ。
理解せずに使ってると、「あれ?発火してないのにレンダリングされてる?」みたいなモヤつきを抱えることにはなりそうなので理解はしておいた方が良さそう。
IEサポート終了
🙏
useDeferredValue も必要に応じて使える
一般的に言うデバウンスをReactのレンダリングに対して行うためのフック。
デバウンスとは、大量に流れてくるイベントに対して毎度処理を行うのではなく、最後のイベントが発火されてから一定時間経過したら処理を行うようにするテクニックのこと。
典型的なのはブラウザのリサイズイベントとかスクロールイベントを検知してアレコレする処理とか。
Reactにおいてのデバウンスというのは、例えば input の onChange の中でレンダリングが発火するような処理を書いている場合に、従来ならユーザーの入力時に1文字ずつレンダリングが発火するけど、それをデバウンスできる。
そうすることで、ユーザーの文字入力がカクつくような問題を回避できることも。