React の新しいメジャー バージョンの更新ノートは常に信じられないほど情報が密集しており、フレームワーク自体が非常に幅広いため、私は常にメモを取ったり、リファレンス ドキュメントと比較したりして、何が変更され、どのように使用されるかだけでなく、アップデートノートで説明されているさまざまな主要な概念が実際に内部でどのように機能するかを理解します。 React は非常に詳しく文書化されていますが、更新ノートは概念を理解するのに常に「十分」であるとは限りません。たとえば、React 19 の更新ノートでは、useOptimistic の例がわかりにくく、実際にフックがどのように機能するかについては実際に少し不正確であることがわかりました。
私は、React 19 の変更点を検討する際に取ったメモを、メモを調べてその意味を理解するのを恐れている人たちのお供として書くことにしました。それでは、始めましょう。
アクションとフォーム処理/useActionState
最初の大きな改善は、フォーム処理の大幅な改善です。 React はボイラープレートを削除し、ネイティブ HTML フォームとより適切に統合する方向に徐々に移行しており、その新しい useActionState はこの推進の一部です。これはエラー処理を改善することを目的としており (現在組み込まれているため)、読み込み状態を自動的に追跡するため、常に保留状態で手動でコーディングする必要がなく、プログレッシブ エンハンスメントのサポートが向上します。
useActionState に提供されているコード例は非常にわかりにくいことがわかりました。実際、このコード例がこの記事を書き始めたすべての理由です。実際には、useActionState には 2 つの部分があり、それらは 2 つの部分で結合されています。スペースを節約するための例ですが、最終的には鮮明さが大幅に低下します。 useActionState は、フォーム送信の非同期アクションがいつ完了したかを追跡するタプルを返しますが、渡したアクションの修正バージョンはフォームに直接渡されます。 useActionState 自体は、非同期 formAction (呼び出されたときに前の状態とフォーム データの両方を引数として受け取ります) と初期状態の 2 つの入力を受け取ります。初期状態は null、ゼロ、または変数にすることができます。
フォームがまだ送信されていない場合、以前の状態が初期状態になります。フォームが以前に送信されている場合は、送信された内容がそのまま反映されます。サーバー関数では、ハイドレーションが発生する前にサーバーの応答を実際に表示できます。最後に useActionState は、フォームが変更することを目的とした一意のページ URL を含む文字列を受け入れることができます。 つまり、オプションのパーマリンク パラメータも受け入れることができます。これは、プログレッシブ エンハンスメントに特に役立ちます。これは、JavaScript が読み込まれる前にユーザーがフォームを送信した場合にブラウザに移動先を指示します。
最後に、useActionState が返すタプルは、現在の状態 (最初のレンダリング中は初期状態の値です)、アクションとしてフォームに渡すことができる、またはプロップとしてボタンに渡すことができる反応修正された formAction で構成される配列です。 isPending フラグ/ステートフル変数。これは特に便利そうなので、React チームが他にどのような新しい開発を思いつくか楽しみにしています。
React-DOM の更新
<フォーム>アクション
この React-dom の追加は、NextJS とフォーム アクションを使用している人なら誰でもよく知っているでしょう。Reac チームはフォーム アクションがプライムタイムに対応できると判断したようです。 NextJS や React 上の別のフレームワークでこれらを使用したことがない人にとって、これらは基本的に、ネイティブ フォーム送信を使用して React のパフォーマンスを向上させる方法です。 onClick の代わりに、アクション プロパティを介してネイティブ フォームの送信を渡すことができます。アクションまたは formAction に渡される関数は、その送信が自動的に処理されます。 React は、制御されていないフォーム フィールドも自動的にリセットします。 API 経由でリセットする手動オプションもあります。 React チームは、エラー境界を使用したエラー処理も統合しました。 ほとんどの人が NextJS で覚えていると思うので、これについてはあまり話しませんが、質問がある場合はフォローアップを書きます。
useFormStatus フック
これは、プロップドリルやコンテキストを使用せずに、フォーム内で何が起こっているかを確認するのに役立つ優れた追加機能です。なぜプロップドリルしないのかと言うと、コードを保守しやすく、変更しやすくするためです。 コンテキストに関しては、コンテキスト内の何かが変更されるたびに、特定のコンテキストにサブスクライブされているすべてのコンポーネントが再レンダリングされるため、コンテキストを過度に使用するとパフォーマンスの問題が発生します。 したがって、コードが整理され、エラーの可能性が減り、アプリのパフォーマンスをごまかしてしまうことがなくなります。
フックは 4 つのプロパティを持つオブジェクトを返します: pending - 保留中の送信があるかどうかを示すブール値、 data - 親フォームによって送信されたデータを含む formData オブジェクト (アクティブな送信または親フォームがない場合、これは null です) )、メソッド (get または post)、およびアクション - アクション プロパティを介して渡されるアクションです。
useOptimistic フック
楽観的な更新を管理するための新しい簡単な方法。 オプティミスティック更新に慣れていない方のために説明すると、これは、サーバー側の更新が行われる前にクライアント側の表示を更新することを意味します。 何かを気に入ったことがあり、アニメーションの再生を見て、それを画面にお気に入りとして登録した後、「いいねは失敗しました」というトースト エラーが表示された場合、これは楽観的なレンダリングが原因です。
useOptimistic フックは、オプティミスティックにレンダリングしたいステートフル変数と、純粋な関数、つまり副作用のない決定論的な関数である必要がある更新関数を受け入れます。基本的に、update 関数は状態への更新のソースを取得します。したがって、通常は formData.get(‘name’) のようなものになります。 useOptimistic は、オプティミスティック状態と addOptimistic 関数の 2 つの値を返します。
このドキュメントは、特に使用フローに関して少し弱いと思いました。基本的には、useOptimistic を呼び出し、オプティミスティックな更新を表示する初期状態と更新関数を渡します。新しくオプティミスティックに強化されたステートフル値 (optimisticState) とオプティミスティックに状態を変更する関数の 2 つの関数を受け取ります。ユーザーによって送信された新しい値がある場合、ドキュメントでは addOptimistic と呼ばれる 2 番目の関数を呼び出し、ユーザーが送信した値を渡します。ステートフル変数をオプティミスティックにレンダリングしたい場合は、コンポーネント内でオプティミスティック拡張ステートフル値を渡します。
全体的に、私はオプティミスティックな更新を実行するこのより標準化された方法がとても気に入っています。私は以前、NextJS でのキャッシュとオプティミスティックな更新の作成に問題を抱えていたので、オプティミスティックな更新を作成する標準化された方法は素晴らしいです。そして、これはきっと役に立つでしょう。 NextJS をバブルアップしていない場合は、バブルアップします。
使用 API
これは非常に高密度な API であり、React がページをレンダリングしている間にリソースにアクセスするまったく新しい方法です。使用されている正確な表現は「レンダリングでリソースを読み取る」です。では、具体的には何のためにあるのでしょうか? この新しい API を使用すると、条件文またはループ内のコンポーネント情報にアクセスできます。 これがなぜ便利なのかよく分からない方のために説明すると、これは React のレンダリング プロセスがどのように機能するかに関係しています。 React/react-fiber は、毎回すべてを同じ順序でレンダリングすることに依存しているため、通常、レンダリング プロセス中にほとんどのフックにアクセスできません。 より明確に言うと、状態は実際にはフックが呼び出される順序に基づいて追跡されるため、フックが予測できない順序で呼び出される場合、レンダリングのバグが発生します。良い例は、ユーザーがログインしているかどうかに応じてテーマ コンテキストにアクセスすることです。
それでは、なぜこれが重要な進展なのでしょうか? これは、実際に必要な場合にのみ情報/データをロードできることを意味します。ユーザーが実際にログインしている場合にのみ、特別なテーマの CSS がロードされます。データはシリアル化可能である必要があるため、プロミスが実際に実行されている間に、サーバー コンポーネントからクライアント コンポーネントに Promise を送信できることになります。これは、ウォーターフォール リクエストが少なくなり、自動的に並列化されることを意味します。 サーバー コンポーネントで作業する場合、実際には、データのフェッチに使用するよりも async/await を使用することを優先する必要があることに注意してください。これは、async/await は中断したところから正確にレンダリングを再開するのに対し、使用すると完全な再レンダリングがトリガーされるためです。データ解決後のコンポーネント。もちろん、この変更は、実際には、使用の設定を誤った場合に、ウォーターフォール リクエストの潜在的なソースが新たに存在することを意味することにも注意しておきたいと思います。
注意すべき重要な点の 1 つは、try/catch ブロックで「use」API を使用できないことです。これは、「use」が Promise で呼び出されたときに自動的にリアクション サスペンス境界を使用するためです。 try/catch ブロックにより、React レベルに到達することができなくなります。エラーが発生すると、React に到達する前に実際に JS レベルでの実行が停止し、機能が中断されてしまうためです。 他のフックと同様に、フックは特定のコンポーネントまたは関数のスコープの最上位に存在する必要があります (これもレンダリング順序のため)。
つまり、「使用」の実際の目的は、コンテキストにアクセスして条件付きでレンダリングし、実際に必要な場合にのみデータをフェッチできるようにすることです。これは、react の難解さをもう少し軽減し、条件付きデータの取得を簡素化し、開発エクスペリエンスを向上させ、パフォーマンスを一気に向上させるためのもう 1 つのステップです。経験豊富な React 開発者は、テーマ設定などの方法を再学習する必要がありますが、これにより、新しいユーザーにとってフレームワークがはるかにアクセスしやすくなり、常に素晴らしいことだと思います。
新しい React Dom 静的 API
これら 2 つの新しい静的 API、prerender と prerenderToNodeStream は、どちらもサーバー サイド レンダリング (SSR) に使用される renderToString の改良版です。これらの新しい改善は、renderToString を使用して静的サイト生成 (SSG) を実行するためのものです。 コンテンツ チャンクが利用可能になると送信できる従来のストリーミング SSR とは異なり、これらの新しい API は、最終的な HTML を生成する前にすべてのデータがロードされるのを特に待ちます。これらは、Node.js ストリームや Web ストリームなどの最新のストリーミング環境とシームレスに連携するように設計されていますが、部分コンテンツのストリーミングは意図的にサポートしていません。代わりに、ビルド時に完全で完全に読み込まれたページを確実に取得できるようにします。これらは、データが利用可能になると事前にレンダリングされたサイトを送信する従来のストリーミング SSR 方式とは異なります。
NextJS など、React 上に構築された SSG 対応フレームワークはすでにありましたが、これは SSG 用の React のネイティブ機能であることを目的としています。 SSG を備えたフレームワークは renderToString を使用し、それを中心に独自の複雑なデータ取得調整を構築しました。 これをユーザーが自分で作成するのは非常に困難であり、これらのフレームワークはそのために非常に複雑なパイプラインを使用していました。 これらの新しいメソッドは基本的に、静的 HTML の生成中にデータをロードできるようにします。SSG に詳しくない場合は、基本的にビルド時にすべてをレンダリングし、間違いなくページをレンダリングする最速の方法です。ユーザーのリクエストに応じてページをレンダリングするため、Vercel でのデプロイメントまたは非常に複雑なデプロイメント プロセスが必要な Next のようなものを使いたくない人にとって、この種の機能があるのは素晴らしいことです。
サーバーコンポーネント
React サーバー コンポーネントの概念は、NextJS の最新バージョンを使用したことがある人にとっては目新しいものではありませんが、まだ使用していない人にとっては、サーバー コンポーネントはデータ取得に関する新しいパラダイムです。率直に言って、サーバー コンポーネント (およびサーバー アクション) の概念自体は記事全体を書く価値がありますが、概念を簡単に要約すると、サーバー コンポーネントは、JavaScript がロードされた後でも、クライアントに送信される前に常にサーバー上でレンダリングされます。 つまり、後続のレンダリングはサーバー側で行われます。
これらのコンポーネントの主な利点は、セキュリティとデータの取得です。サーバー コンポーネント内でデータをリクエストした場合、リクエスト情報はクライアント側には表示されず、応答のみが表示されるため、安全性が大幅に高まります。 API、エンドポイントなどはクライアント側からはアクセスできません。また、前述のアクションの JavaScript がクライアントに送信されないため、バンドル サイズも削減されます。さらに、サーバー上でメモリや計算負荷の高い操作を実行して、非強力なマシンでのレンダリングの負担を軽減することもできます。 また、データベースに近いマシンで順次データの取得を実行できるため、クライアント側のウォーターフォールも削減されますが、もちろん、開発者がテスト ブラウザ開発者からの簡単なリクエスト情報にアクセスできなくなるため、まったく新しいサーバー側のウォーターフォールが発生する可能性も広がります。ツールがあり、それらを調べるには OpenTelemetry コレクターやビューアーなどを使用する必要があります。最後に、サーバー コンポーネントは、段階的な機能強化にも最適です。
サーバー コンポーネントには制限のリストもあります。ローカル ブラウザ API (ローカル ストレージ、ウィンドウなど) は使用できません。反応フックの動作は異なります。状態に依存したり使用したりすることはできません。イベント ハンドラーを使用しないため、コンポーネントに対するユーザーの対話性は明らかに希薄です。 基本的に、このパラダイムは、サーバー コンポーネントでのデータの取得、クライアント コンポーネントでの対話機能として考えてください。
サーバー コンポーネントを初めて使用する人にとって最も重要な注意点は、サーバー コンポーネントをクライアント コンポーネントにインポートできないことです。インポートすると、コンパイラーが上記のコンポーネントを処理するため、エラーが発生します (データの取得を追加したと仮定して)。サーバーコンポーネントをクライアントコンポーネントとして使用します。サーバー コンポーネントをクライアント コンポーネントに渡したい場合は、それを {children} プロパティ経由で渡す必要があります。
サーバーアクション
これらは、製品や機能の構築方法に多くの影響を与えるもう 1 つの複雑なトピックであり、これらは 1 年ほど前から NextJS にも存在しています。 サーバーアクションは、ファイルの先頭に「useserver」と入力することで宣言され、クライアントコンポーネントの内部から呼び出すことができるサーバー関数への直接参照を渡します。
これらは、概念的にはリモート プロシージャ コール (RPC) に似ています。どちらもクライアントからサーバー側の関数を呼び出すことができ、クライアントとサーバーのやり取りの複雑さを抽象化し、シリアル化と逆シリアル化を処理しますが、注意すべき重要な違いがいくつかあります。 サーバー アクションの主な利点は、React のプログレッシブ機能強化と連携し、クライアント/サーバーの境界を越えてタイプ セーフティを強制するのに役立ち、パフォーマンスの最適化 (プログレッシブな機能強化に関連する) が組み込まれており、React エコシステムとよりシームレスに統合できることです。つまり、組み込みの保留状態が提供され、ネイティブ フォームの送信と自動的に統合されます。
最新の RPC、つまりタイプ セーフティとパフォーマンスの最適化がすでに備わっている gRPC のようなものについて話している場合、サーバー アクションの主な利点は一般に、組み込みのフォーム処理とプログレッシブ機能強化に集約されますが、重要なのは、それが機能することでもあるということです。反応のサスペンスとエラーの境界があります。最も重要なことは、gRPC 用に別のサーバーをセットアップする必要がないため、デプロイがはるかに簡単であるということです。そのため、小規模なプロジェクトには絶対に理想的ですが、大規模なプロジェクトとなると、gRPC の方がはるかに望ましいことがわかります。バックエンド言語などの点で柔軟性が高まります。
プロバイダとしてのコンテキスト
これは本質的に構文の簡略化であり、React がよりクリーンで宣言的な構文を持つのに役立ちます。 正直に言うと、「気に入った」以外にこれについて言うことはあまりありません。
Prop としての参照と参照のクリーンアップ関数
以前は、ref をクリーンアップするには、コンポーネント内で null チェックを実行する必要があり、ref はある程度不定の時点でクリーンアップされていました。 React は、コンポーネントがアンマウントされると、null を使用して ref コールバックを呼び出すため、アタッチとデタッチの両方のケースを明示的に処理する必要があります。新しい ref 構文の利点は決定論的なクリーンアップです。これは、ref クリーンアップがいつ (アンマウント時) に行われるかを正確に知ることができるため、外部リソースやサードパーティ ライブラリの操作がはるかに簡単になることを意味します。 新しいアプローチでは、クリーンアップ関数を直接返すことができます。 TypeScript の統合では、クリーンアップ関数に関する曖昧さを避けるために、明示的な return ステートメントが必要です。
useEffect と同じパターンなので、この実装方法がとても気に入っています。フレームワーク全体で一貫性を維持するのは素晴らしいことです。この新しい ref クリーンアップは、特に WebGL コンテキストやその他の重いリソースだけでなく、ネイティブ JS メソッドを使用して追加された DOM イベント リスナーの処理にも非常に役立つと思います。 これは、以前は、react がクリーンアップ時に dom 要素への参照を削除していたためです…しかし、それを行った場合、イベント リスナーがアタッチされているコンポーネントへの参照が失われるため、イベント リスナーを削除するのがはるかに複雑になります。 。 その結果、要素の外部に参照を保存する必要があり、複雑さがさらに増しました。これで、コンポーネントの return 関数内の ref へのアクセスが保持されるため、コンポーネントの return 関数内のイベント リスナーを削除するだけで済みます。これは、クリーンアップ関数を使用するときに React が null で ref を呼び出すことがなくなるため、ほとんどの状況で null の場合を心配する必要がなくなったことも意味します。クリーンアップ関数自体がその機能を置き換えることで、コードがよりクリーンになり、予測可能になります。
useDeferredValue
useDeferredValue フックの目的は、応答性の高いユーザー インターフェイスを維持しながら、計算量の多い操作を管理することです。これは、バックグラウンドで新しいデータを計算または取得しているときに、コンポーネントが以前の「古い」値を表示できるようにすることで実現します。一般的な使用例は、ユーザーが入力したときに結果を表示する検索機能です。保留しないと、キーストロークごとにコストのかかる検索操作がトリガーされ、入力が遅く感じる可能性があります。 useDeferredValue を使用すると、新しい検索結果を計算しながら以前の検索結果を表示することで、インターフェイスの応答性を維持できます。
この新しい追加は、このフックの初期読み込み動作に対する重要な改善です。以前は、最初のレンダリングでは useDeferredValue に渡された値がすぐに使用され、開始時に負荷の高い計算がトリガーされる可能性がありました。新しいバージョンでは、より高価な値をバックグラウンドで処理しながら、すぐに表示される軽量の初期値 (空の文字列など) を提供できます。これは、安全なデフォルト値を使用してユーザーに即時にフィードバックを表示し、高価な計算が完了したら実際のデータで更新できることを意味します。基本的に、これにより useDeferredValue のパフォーマンス向上がさらに向上します。
ドキュメントのメタデータの追加
これらの新しい変更は、実際のコンポーネント内にさまざまなメタデータ タグを追加するためのものです。対象となるオプションは、、
これらの変更による主な利点は、コンポーネントが完全に自己完結型になることです。コンポーネントは、スタイルやスクリプトとともに独自のメタデータを管理できるようになりました。メタデータを最上位レベルに引き上げる方法を考えたり、そのためにライブラリを使用したりする必要がなくなり、SEO がはるかに簡単になります。 SPA 内のさまざまなページに、より簡単に異なるメタデータを持たせることができます。これまでは、ページごとに異なるメタデータを持つ場合にリスクであった、メタデータがページに表示されるコンテンツと同期しなくなるリスクを回避できます。
スタイルシートのサポート
人々は忘れるほど長い間 tailwind を使用してきたかもしれませんが、カプセル化されていない CSS を実行すると、スタイルシートの読み込み方法、つまり読み込み順序の優先ルールに起因して問題が発生する可能性があります。まず、スタイルのないコンテンツがフラッシュして表示される可能性があります。CSS のダウンロードが完了する前に HTML が読み込まれてレンダリングされるときは常に、完全に白いページとして表示されます。通常は、巨大なフォント サイズとネイティブ画像サイズを備えた 1 列で表示されます。判読できなくなります。
さらに、CSS のロード順序ルールによって別の問題が発生する可能性があります。たとえば、同じ詳細度を持つルールがあり、それらが特定の順序でロードされることが期待されている場合などです。これは、たとえば、テーマにさまざまなオプションがある場合 (ダーク モードなど) に関係します。ダーク モード CSS が最後に読み込まれるように意図されているが、ダーク モード用の CSS ファイルが最初に読み込まれる場合、ダーク モードが明るくなったり、ルールが遵守されているアプリの一部の部分とそうでない部分が発生したりする可能性があります。遵守しました。
JS の CSS のように、すべての CSS を
にロードするなど、これを回避するための解決策はたくさんありました。ただし、これらの新しい CSS の変更は、宣言的に優先順位を設定することで、これらの問題の管理を支援することを目的としています。また、コンポーネント内に配置されたスタイルシートは、コンポーネント自体がレンダリングされる前に確実に読み込まれるようになります。 また、重複排除機能も組み込まれているため、スタイルシート リンクが含まれるコンポーネントを再利用するときに、同じスタイルシートを何度も読み込む必要がなくなります。この新しい機能にアクセスする方法 (コンポーネントをレンダリングする前に CSS がロードされるのを待つ、CSS を自動的に head に巻き上げるなど) も非常に簡単です。特定の
非同期スクリプトのサポート
これは、人々が心配するような新しいコア機能を作成するのではなく、特殊なケースに対処します。