renderToPipeableStream


リファレンス

renderToPipeableStream(reactNode, options?)

renderToPipeableStream を呼び出して、React ツリーを HTML として にレンダーします。

クライアント側では、このようにサーバ生成された HTML を操作可能にするために を用います。

引数

  • reactNode: HTML へとレンダーしたい React ノード。例えば、<App /> のような JSX 要素です。これはドキュメント全体を表すことが期待されているため、App コンポーネントは <html> タグをレンダーする必要があります。

  • 省略可能 options: ストリーム関連のオプションが含まれたオブジェクト。

    • 省略可能 bootstrapScriptContent: 指定された場合、この文字列がインラインの <script> タグ内に配置されます。
    • 省略可能 bootstrapScripts: ページ上に出力する <script> タグに対応する URL 文字列の配列。これを使用して、 を呼び出す <script> を含めます。クライアントで React をまったく実行したくない場合は省略します。
    • 省略可能 bootstrapModules: bootstrapScripts と同様ですが、代わりに を出力します。
    • 省略可能 identifierPrefix: React が によって生成する ID に使用する文字列プレフィックス。同じページ上に複数のルートを使用する際に、競合を避けるために用います。 にも同じプレフィックスを渡す必要があります。
    • 省略可能 namespaceURI: このストリームのルート 文字列。デフォルトでは通常の HTML です。SVG の場合は 'http://www.w3.org/2000/svg'、MathML の場合は 'http://www.w3.org/1998/Math/MathML' を渡します。
    • 省略可能 nonce: を用いてスクリプトを許可するための 文字列。
    • 省略可能 onAllReady: とすべての追加の両方を含むすべてのレンダーが完了したときに呼び出されるコールバック。の場合に、onShellReady の代わりに利用できます。ここからストリーミングを開始する場合、プログレッシブなローディングがなくなり、ストリームには最終的な HTML が含まれるようになります。
    • 省略可能 onError: サーバエラーが発生するたびに発火するコールバック。の場合もの場合もあります。デフォルトでは console.error のみを呼び出します。これを上書きして場合でも console.error を呼び出すようにしてください。また、シェルが出力される前にためにも使用できます。
    • 省略可能 onShellReady: がレンダーされた直後に呼び出されるコールバック。ここでを行い、pipe をコールしてストリーミングを開始できます。React はシェルを送信した後に、と、ローディングフォールバックを追加コンテンツで置換するためのインライン <script> タグをストリーミングします。
    • 省略可能 onShellError: 初期シェルのレンダー中にエラーが発生すると呼び出されるコールバック。引数としてエラーを受け取ります。ストリームからのバイト列送信はまだ起きておらず、onShellReadyonAllReady はコールされなくなるため、することができます。
    • 省略可能 progressiveChunkSize: チャンクのバイト数。。

返り値

renderToPipeableStream は以下の 2 つのメソッドを含んだオブジェクトを返します。

  • pipe: HTML を に出力します。pipe の呼び出しは、ストリーミングを有効にしたい場合は onShellReady で、クローラや静的生成向けの出力を行いたい場合は onAllReady で行ってください。
  • abort: してクライアントで残りをレンダーするために使用します。

使用法

React ツリーを HTML として Node.js ストリームにレンダーする

renderToPipeableStream を呼び出して、React ツリーを HTML として にレンダーします。

ルートコンポーネントブートストラップ <script> パスのリストを指定する必要があります。ルートコンポーネントは、ルートの <html> タグを含んだドキュメント全体を返すようにします。

例えば以下のような形になるでしょう。

React は とあなたが指定したブートストラップ <script> タグを結果の HTML ストリームに注入します。

クライアント側では、ブートストラップスクリプトは 必要があります。

これにより、サーバで生成された HTML にイベントリスナが追加され、操作可能になります。

さらに深く知る

ビルド出力から CSS と JS のアセットパスを読み取る

ビルド後に、最終的なアセット URL(JavaScript や CSS ファイルなど)にはよくハッシュ化が行われます。例えば、styles.cssstyles.123456.css になることがあります。静的なアセットのファイル名をハッシュ化することで、同じアセットがビルドごとに異なるファイル名になることが保証されます。これが有用なのは、ある特定の名前を持つファイルの内容が不変になり、静的なアセットの長期的なキャッシングを安全に行えるようになるためです。

しかし、ビルド後までアセット URL が分からない場合、それらをソースコードに含めることができません。例えば、先ほどのように JSX に "/styles.css" をハードコーディングする方法は動作しません。ソースコードにそれらを含めないようにするため、ルートコンポーネントが、props 経由で渡されたマップから実際のファイル名を読み取るようにすることができます。

サーバ上では、<App assetMap={assetMap} /> のようにレンダーし、アセット URL を含む assetMap を渡します。

サーバで <App assetMap={assetMap} /> のようにレンダーしているので、クライアントでも assetMap を使ってレンダーしてハイドレーションエラーを避ける必要があります。このためには以下のように assetMap をシリアライズしてクライアントに渡します。

上記の例では、bootstrapScriptContent オプションを使って<script> タグを追加して、クライアント上でグローバル window.assetMap 変数をセットしています。これにより、クライアントのコードが同じ assetMap を読み取れるようになります。

クライアントとサーバの両方が props として同じ assetMap を使って App をレンダーするため、ハイドレーションエラーは発生しません。


ロードが進むにつれてコンテンツをストリーミングする

ストリーミングにより、サーバ上ですべてのデータがロードされる前に、ユーザがコンテンツを見始められるようにすることができます。例えば以下のようなプロフィールページがあり、カバー、フレンド・写真が含まれたサイドバー、投稿のリストを表示しているところを考えましょう。

ここで、<Posts /> のデータを読み込むのに時間がかかるとしましょう。理想的には、投稿の読み込みを待つことなく、プロフィールページの残りのコンテンツをユーザに表示したいでしょう。これを実現するには、。

これにより React に、Posts のデータが読み込まれる前に HTML をストリーミング開始するよう指示します。React はまず、ローディングフォールバック (PostsGlimmer) の HTML を送信します。次に Posts のデータ読み込みが完了したら、残りの HTML と、ローディングフォールバックをそれで置換するためのインライン <script> タグを送信します。ユーザから見ると、ページにはまず PostsGlimmer が表示され、後からそれが Posts に置き換わることになります。

さらに、より細かく読み込みシーケンスを制御するために。

この例では、React はページのストリーミングをさらに素早く開始できます。最初にレンダーが完了している必要があるのは、<Suspense> バウンダリで囲まれていない ProfileLayoutProfileCover だけです。SidebarFriendsPhotos がデータを読み込む必要がある場合、React は BigSpinner のフォールバック HTML を代わりに送信します。その後、より多くのデータが利用可能になるにつれ、より多くのコンテンツが表示されていき、最終的にすべてが表示されます。

ストリーミングでは、ブラウザで React 自体が読み込まれるのを待つ必要も、アプリが操作可能になるのを待つ必要もありません。サーバからの HTML コンテンツは、あらゆる <script> タグが読み込まれる前にプログレッシブに表示されます。


シェルに何を含めるかの指定

アプリの全 <Suspense> バウンダリより外にある部分のことをシェル (shell) と呼びます。

これが、ユーザに見える最初のローディング中状態を決定します。

もしルート部分でアプリ全体を <Suspense> バウンダリでラップしてしまうと、シェルとしてはそのスピナだけが含まれることになります。しかしこれはあまり快適なユーザ体験にはなりません。大きなスピナが画面に表示されることは、もう少しだけ待ってから実際のレイアウトを表示することよりも遅く不快に感じられるためです。したがって、<Suspense> 境界は適切に配置して、シェルがミニマルかつ完全に感じられるように必要があるでしょう。例えばページレイアウト全体のスケルトンのようなものです。

シェル全体のレンダーが完了したときに onShellReady コールバックが呼び出されます。通常、ここでストリーミングを開始します。

onShellReady が呼び出される時点では、ネストされた <Suspense> バウンダリ内のコンポーネントはまだデータをロード中かもしれません。


サーバ上でのクラッシュログの記録

デフォルトでは、サーバ上のすべてのエラーはコンソールにログとして記録されます。この挙動をオーバーライドして、クラッシュレポートをログとして記録することができます。

カスタムの onError 実装を提供する場合、上記のようにエラーをコンソールにもログとして記録することを忘れないでください。


シェル内のエラーからの復帰

この例では、シェルとして ProfileLayoutProfileCover、および PostsGlimmer が含まれています。

これらのコンポーネントをレンダーする際にエラーが発生した場合、React はクライアントに送信できる意味のある HTML を提供できません。最終手段として、onShellError をオーバーライドして、サーバレンダリングに依存しないフォールバック HTML を送信しましょう。

シェルの生成中にエラーが発生した場合、onErroronShellError の両方が発火します。エラーレポートには onError を使用し、フォールバックの HTML ドキュメントを送信するためには onShellError を使用します。フォールバック HTML はエラーページである必要はありません。代わりに、クライアントのみでアプリをレンダーするための代替シェルを含めることも可能です。


シェル外のエラーからの復帰

この例では、<Posts /> コンポーネントは <Suspense> でラップされているため、シェルの一部ではありません

Posts コンポーネントまたはその内部のどこかでエラーが発生した場合、React はそこからの。

  1. 最も近い <Suspense> バウンダリ (PostsGlimmer) のローディングフォールバックを HTML として出力します。
  2. サーバ上で Posts のコンテンツをレンダーしようとするのを諦めます。
  3. JavaScript コードがクライアント上でロードされると、React はクライアント上で Posts のレンダーを再試行します。

クライアント上で Posts のレンダーを再試行して再度失敗した場合、React はクライアント上でエラーをスローします。レンダー中にスローされる他のすべてのエラーと同様に、がユーザにエラーをどのように提示するかを決定します。つまり、エラーが復帰不能であることが確定するまで、ユーザにはローディングインジケータが見えることになります。

クライアント上での Posts のレンダー再試行が成功した場合、サーバからのローディングフォールバックはクライアントでのレンダー出力で置き換えられます。ユーザにはサーバエラーが発生したことは分かりません。ただし、サーバの onError コールバックとクライアントの コールバックが発火するため、エラーについて通知を受け取ることができます。


ステータスコードの設定

ストリーミングにはトレードオフも存在します。ユーザがコンテンツを早く見ることができるように、できるだけ早くページのストリーミングを開始したいでしょう。一方で、ストリーミングを開始すると、レスポンスのステータスコードを設定することができなくなります。

シェル(すべての <Suspense> バウンダリより上の部分)とそれ以外のコンテンツにことで、この問題はすでに部分的に解決されています。シェルでエラーが発生した場合、onShellError コールバックが呼び出され、エラーのステータスコードをセットすることができます。それ以外の場合は、アプリがクライアント上で復帰できる可能性があるため、“OK” を送信できるのです。

シェルの外側(つまり <Suspense> バウンダリの内側)のコンポーネントでエラーが発生した場合、React はレンダーを停止しません。これは、onError コールバックは発火するものの、その後 onShellError ではなく onShellReady が発火することを意味します。これは、React がそのエラーをクライアント上で復帰しようとするからです。

ただしお望みであれば、何らかのエラーが起きたという事実に基づいたステータスコードを設定することもできます。

これは、初期のシェルコンテンツの生成中に既にシェルの外側で発生したエラーが捕捉できるだけなので、完全ではありません。あるコンテンツでエラーが発生したかどうかを知ることが重要であれば、それをシェルに移動させることができます。


エラーの種類によって処理を分ける

カスタムの Error サブクラスをし、 演算子を使用してどんなエラーがスローされたかをチェックすることができます。例えば、カスタムの NotFoundError を定義し、コンポーネントからそれをスローすることができます。その後、onErroronShellReady, onShellError のコールバック中でエラーの種類に応じて異なる処理を行うことができます。

しかしシェルを出力してストリーミングを開始してしまうと、ステータスコードを変更できなくなりますので注意してください。


クローラや静的生成向けに全コンテンツの読み込みを待機する

ストリーミングにより、利用可能になった順でコンテンツをユーザが見えるようになるため、ユーザ体験が向上します。

しかし、クローラがページを訪れた場合や、ビルド時にページを生成している場合には、コンテンツを徐々に表示するのではなく、すべてのコンテンツを最初にロードしてから最終的な HTML 出力を生成したいでしょう。

onAllReady コールバックを用いることで、すべてのコンテンツが読み込まれるまで待機を行うことができます。

通常のユーザは、ストリームで読み込まれるコンテンツを段階的に受け取ります。クローラは、全データが読み込まれた後の最終的な HTML 出力を受け取ります。しかし、これはクローラがすべてのデータを待つ必要があることを意味し、その中には読み込みが遅いものやエラーが発生するものも含まれるかもしれません。アプリケーションによっては、クローラにもシェルを送信することを選択しても構いません。


サーバレンダリングの中止

タイムアウト後にサーバでのレンダーを「諦める」ように強制することが可能です。

React は、残りのローディング中フォールバックを HTML として直ちに出力し、クライアント上で残りをレンダーしようと試みます。