React: 2022年6月における開発状況

React公式サイトのBlog記事「[React Labs: What We've Been Working On – June 2022](https://reactjs.org/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.html)」が、2022年6月における開発状況について記しています。新機能に向けた考えをコミュニティと共有しようということです。本稿はBlog記事に沿って、内容をかいつまんでご説明します。

なお、記事の情報はロードマップではありません。現在、検討と開発が進められている問題領域を示したものです。はっきりとした出荷時期は決まっていないことをご了承ください。


# サーバーコンポーネント
2020年12月に[Reactサーバーコンポーネント](https://reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html)(React Server Component)の実験的なデモが発表されました。その後、React 18で依存関係は仕上がり、フィードバックをもとに手が加えられています。

とくに、I/Oライブラリをフォークする(react-fetchなど)という考え方は捨て去りました。かわりに用いられたのが、互換性の高いasync/awaitモデルです。データの取得にルータも使えるので、技術的にReactサーバーコンポーネントのリリースは妨げられません。もうひとつ変わったのは、ファイル拡張子のアプローチから、[境界の注釈](https://github.com/reactjs/rfcs/pull/189#issuecomment-1116482278)(annotating boundaries)に移行したことです。

また、VercelならびにShopifyと協力して、WebpackおよびViteの両方で共有セマンティクスのバンドラーサポートを統合しています。リリース前に、Reactサーバーコンポーネントのセマンティクスが、Reactエコシステムをとおして同じであるか確かめなければなりません。安定性を得るための、大きな障害となるからです。


# アセットのロード
現在、スクリプト、外部スタイル、フォント、画像などのアセットは、通常外部システムを用いてプリロードされ、読み込まれます。このため厄介になりそうなのが、ストリーミングやサーバーコンポーネントなど、新しい環境にまたがった調整です。そこで、外部アセットが重複なくプリロードおよびロードできるAPIを加えて、すべてのReact環境で機能するReact APIの検討も進められています。

併せて考えているのが、Suspenseによるサポートです。画像、CSS、フォントは読み込まれるまで表示されません。他方で、ストリーミングや同時レンダリングは妨げられないのです。飛び跳ねるビジュアルでレイアウトがシフトする「[ポップコーニング](https://twitter.com/sebmarkbage/status/1516852731251724293)」を避けられます。


# 静的サーバーレンダリングの最適化
静的サイト生成(Static Site Generation)とインクリメンタル静的再生(Incremental Static Regeneration)は、キャッシュ可能なページのパフォーマンスを高める優れた方法です。けれど、動的なサーバーサイドレンダリング(Server Side Rendering)のパフォーマンスを上げる機能も加えることができます。ほとんどの場合、コンテンツはキャッシュ可能です。コンパイルと静的パスを活用してサーバーレンダリングを最適化する方法が模索されています。


# React最適化コンパイラ
React Conf 2021でReact Forgetの[初期プレビュー](https://www.youtube.com/watch?v=lGEMwh32soc)を行いました。これは、`useMemo`と`useCallback`の呼び出しに相当する処理を自動生成するコンパイラです。再レンダリングのコストを最小限に抑え、しかもReactのプログラミングモデルは保持されます。

最近、コンパイラの書き直しが済み、信頼性と機能はさらに高まりました。新しいアーキテクチャにより、より複雑なパターンを解析してメモ化できるようになったのです。[ローカルミューテーション](https://beta.reactjs.org/learn/keeping-components-pure#local-mutation-your-components-little-secret)(local mutation)[^1]を用いたり、単なるメモ化フックを超える多くのコンパイル時の最適化の新しい機会が広がります。

[^1]: 変数やオブジェクトの変更(ミューテーション)はその生成時に、関数内(ローカル)で行うという手法です(「[Local mutation: Your component’s little secret](https://beta.reactjs.org/learn/keeping-components-pure#local-mutation-your-components-little-secret)」参照)。純粋な関数は、スコープ外の変数や呼び出し前につくられたオブジェクトを変更することは許されません。

プレイグラウンドへの取り組みも進んでおり、コンパイラのさまざまな側面が調べられるようになるでしょう。プレイグラウンドの目的は、コンパイラを開発しやすくすることです。さらに、コンパイラを試して、コンパイラが何をするのか直感的に理解できるようになります。内部的にどのように動作しているのか、洞察が深められるのです。そして、コンパイラの出力を入力時にライブレンダリングします。プレイグラウンドは、コンパイラのリリース時に同梱して出荷される予定です。


# オフスクリーン
現在、コンポーネントを非表示にしたり表示するには、ふたつのやり方があります。ひとつは、コンポーネントツリーに対して、丸ごと削除あるいは追加することです。けれど、この方法には問題があります。マウントを外すたびに、UIの状態が失われることです。スクロール位置といったDOMに保存されている状態も含まれます。

もうひとつのやり方は、コンポーネントはマウントしたままにして、CSSにより表示を視覚的に切り替えることです。これでUIの状態は保てます。けれど、問題になるのが、パフォーマンスのコストです。Reactは新たな更新を受け取るたびに、非表示のコンポーネントをレンダリングし続けなければなりません。すると、その子コンポーネントもすべて描画が更新されるのです。

オフスクリーンが導入するのは、3つめのやり方です。UIは視覚的に非表示にします。けれど、コンテンツの優先順位を下げるのです。この考え方はCSSの`content-visibility`プロパティと似ています。隠されたコンテンツは、UIの他の部分と同期させておく必要はありません。Reactはレンダリング処理を、アプリケーションのほかの部分がアイドル状態になるか、コンテンツが再び表示されるまで先延ばしできるのです。

オフスクリーンは低レベルの機能で、高レベルな機能のロックを解除します。 `startTransition`などのReactの他の同時実行機能と同じで、オフスクリーンAPIと直接対話はしません。かわりに、独自のフレームワークにより、つぎのようなパターンを実装するのです。

* **インスタントトランジション**: 一部のルーティングフレームワークは、あらかじめデータをプリフェッチして、あとに続くナビゲーションを高速化します。たとえば、リンクにカーソルを合わせた場合などです。同じように、オフスクリーンを使えば、つぎの画面がバックグラウンドでプリレンダリングできます。
* **再利用可能な状態**: ルートやタブの間を移動するときも、オフスクリーンにより前の画面の状態が保持できるのです。もとに戻って、抜け出したところから再開できます。
* **仮想化されたリストレンダリング**: 大きな項目リストを表示するとき、現在表示されているよりも多くの行を事前にレンダリングするのが仮想化リストフレームワークです。オフスクリーンを用いて、隠れた行を現在リスト表示されている項目より低い優先度でプリレンダリングできます。
* **バックグラウンドコンテンツ**: 関連して検討されているのは、コンテンツは隠すことなくバックグラウンドで優先度を下げる機能です。モーダルオーバーレイを表示するときと同じように考えられます。


# トランジショントレース 
現在、Reactにはふたつのプロファイリングツールがあります。ひとつめは、プロファイリングセッションにおけるすべてのコミットの概要を示すオリジナルの[プロファイラ](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html)です。コミットごとに、レンダリングされたすべてのコンポーネントを表示し、レンダリングにかかった時間も示されます。もうひとつが、React 18に備わった[タイムラインプロファイラ](https://github.com/reactwg/react-18/discussions/76)(ベータ版)です。コンポーネントはいつ更新される予定か、Reactがいつその更新を処理するのか示します。ふたつのプロファイラは、ともに開発者がコードにおけるパフォーマンスの問題を探るのに役立つでしょう。

開発者にとって、個々のコミットやコンポーネントをコンテクストから知っても、さほど役に立たないようです。実際にコミットの遅くなる原因について知る方が、より大切といえます。また、開発者が求めるのは、特定のインタラクション(ボタンのクリック、初期読み込み、ページナビゲーションなど)を追跡できることです。そうすれば、パフォーマンスの低下を監視して、なぜインタラクションが遅くなるのか知り、どう修正すればよいかもわかります。

以前、この問題を解決しようとしてつくられたのが[インタラクショントレースAPI](https://gist.github.com/bvaughn/8de925562903afd2e7a12554adcdda16)です。けれども、根本的な設計上の欠陥がありました。その結果、インタラクションの遅れる理由を追跡する精度が低くなり、インタラクションの終わらないことさえ生じたのです。これらの問題により、このAPIは削除されることになりました。

これらの問題を解決する、新たなバージョンの開発が進んでいます(`startTransition`で起動するのでトランジショントレースと仮称)。


# 新たなReactドキュメント
昨年、Reactドキュメントの新しいサイトが[ベータ版](https://beta.reactjs.org/)として発表されました。新しい学習教材がまず教えるのは、関数コンポーネントをもとにしたフックです。図やイラストも新たに、多くのインタラクティブな作例と課題も備わっています。その作業は一時中断し、React 18のリリースに注力しました。はれてReact 18がリリースされたので、新しいドキュメントの仕上げと公開に向けて、活発な作業が進められている最中です。

現在は、エフェクトについての詳しい章の作成が進んでいます。Reactの初心者と経験者のどちらにとっても、難しい課題のひとつのようだからです。「[Synchronizing with Effects](https://beta.reactjs.org/learn/synchronizing-with-effects)」(エフェクトとの同期)がシリーズの最初に公開され、これから数週間でさらにページは増えてゆきます。エフェクトの詳細解説を書き始めて気づいたのは、多くの一般的なエフェクトのパターンは、Reactに新たなプリミティブを加えることで簡略化できるということです。「[RFC: useEvent](https://github.com/reactjs/rfcs/pull/220)」(RFCはrequest for comments)で、その最初の考えを共有しました。今のところ初期の研究段階で、まだ検討を繰り返すことになるでしょう。