ホームページ >ウェブフロントエンド >jsチュートリアル >サーバーレンダリングの反応で非同期APIを扱う

サーバーレンダリングの反応で非同期APIを扱う

William Shakespeare
William Shakespeareオリジナル
2025-02-16 11:52:10749ブラウズ

Dealing with Asynchronous APIs in Server-rendered React

キーポイントの概要

概要

  • Reactコードのサーバー側のレンダリングは、読み込み時間を短縮し、SEOの柔軟性を向上させるのに役立ちますが、必要なデータを知る前にアプリケーションをレンダリングする必要があるため、非同期APIの処理は困難です。
  • next.js、Redux Connect、React-Frontloadなどの既存のソリューションには、サーバーレンダリングされたReactコードで非同期APIを扱う際の独自の利点と短所があります。
  • カスタマイズされたソリューションは、2つのサーバー側のレンダリングを実行することで実装できます。API呼び出しと非同期操作を初めて処理し、2回目は最終ページレンダリングの取得データを使用します。
  • カスタマイズソリューションでは、プリフェッチ、ポストフェッチ、プリレンダー、バックエンドのレンダリングなど、コンポーネント内のさまざまな状態を慎重に処理する必要があります。これは、コンポーネントコードのステートメントの場合、複雑な場合によって達成できます。
  • また、カスタマイズされたソリューションでは、Pageリクエストの一部としてプリフェッチデータを送信して検索と交換に追加するために、index.htmlファイルを変更する必要があります。スクリプトタグを使用する場合は、ベース64エンコーディングが必要です。
  • 基本的なReactアプリページを作成したことがある場合、特に遅いデバイスでは、SEOとパフォーマンスの問題が低下する可能性があります。従来のWebサーバーレンダリング(通常はnodejsを使用)を追加できますが、これは特に非同期APIを扱う場合は簡単なプロセスではありません。

サーバー側のレンダリングコードの2つの主な利点は次のとおりです。

速度を上げる速度

SEOの柔軟性の向上
  • GoogleがJavaScriptがロードされるのを待つことを忘れないでください。そのため、タイトルコンテンツなどのシンプルなコンテンツは問題なく変更されます。 (しかし、他の検索エンジンで何が起こるか、またはこれがどれほど信頼できるかは言えません。)
  • この記事では、サーバーレンダリングのReactコードを使用する際に、非同期APIからデータを取得する方法について説明します。 Reactコードには、JavaScriptに組み込まれたアプリケーション構造全体があります。これは、コントローラーを使用した従来のMVCモードとは異なり、アプリケーションがレンダリングする前に必要なデータがわからないことを意味します。 Create Reactアプリなどのフレームワークを使用すると、高品質の作業アプリケーションをすばやく作成できますが、クライアント側でのみレンダリングを処理する必要があります。これには、パフォーマンスの問題と、必要に応じてヘッダーを変更できるSEO/データの問題があります。

質問

Reactは主にレンダリングを同期するため、データがない場合、ロード画面がレンダリングされ、データが到着するのを待ちます。レンダリングの前に必要なものがわからないか、必要なものがわかっているが、レンダリングしたため、これはサーバー側ではうまく機能しません。 この標準レンダリング方法を表示:

質問:

  1. これは、ルート要素を探してレンダリングするDOMです。これは私のサーバーに存在しないため、それを分離する必要があります。
  2. メインルート要素の外側にアクセスすることはできません。 Facebookタグ、タイトル、説明、さまざまなSEOタグを設定することはできません。また、要素の外側の残りのDOM、特にヘッダーを制御することはできません。
  3. いくつかの状態を提供しますが、サーバーとクライアントには異なる状態があります。この状態(この場合はredux)に対処する方法を検討する必要があります。

ここで2つのライブラリを使用していたので、非常に人気があるので、使用する他のライブラリに適用できることを願っています。

Redux:ストレージサーバーとクライアントの同期の状態は悪夢の問題です。それは非常に高価であり、多くの場合、複雑なエラーにつながります。サーバー側では、理想的には、物事を機能させて正しくレンダリングするのに十分であることを除いて、Reduxで何もしたくありません。 (通常どおり使用できます。クライアントのように見えるように十分な状態を設定するだけです。)試してみたい場合は、さまざまな分散システムガイドを出発点としてチェックしてください。

React-Router:FYI、これはV4バージョンであり、デフォルトのインストールバージョンですが、古い既存のプロジェクトがある場合は非常に異なります。サーバー側とクライアント側のルーティングを処理し、V4を使用することを確認する必要があります。この点で優れています。

結局のところ、データベース呼び出しを行う必要がある場合はどうなりますか?これは非同期であり、コンポーネントの内側にあるため、突然大きな問題になります。もちろん、これは新しい質問ではありません。公式のReactリポジトリでそれを見る。

必要な依存関係を決定するには、クライアントに提供される前にこれらの依存関係を取得するために必要な依存関係を決定する必要があります。

既存のソリューション

以下では、この問題に現在提供されているソリューションを確認します。

next.js

開始する前に、次の.jsは、サーバー側のレンダリングされたReactコードまたは生産環境のユニバーサルアプリケーションを必要とする場合に最適です。効果的で簡潔で、Zeitのサポートがあります。

しかし、それは意見であり、あなたは彼らのツールチェーンを使用する必要があり、彼らが非同期データロードを処理する方法は必ずしも柔軟ではありません。

next.jsリポジトリドキュメントでコンテンツのこの直接コピーを表示:

<code class="language-javascript">ReactDOM.render(
  <provider> store={store}></provider>
    <browserrouter></browserrouter>
      <app></app>
    >
  >
, document.getElementById('root')
)</code>

getInitialPropsが鍵であり、小道具で満たされたオブジェクトに解決され、ページにのみ存在する約束を返します。何よりも、これはツールチェーンに組み込まれています。

では、データベースデータを取得するにはどうすればよいですか? API呼び出しを行います。したくないの?わかりました、それはひどいです。 (さて、カスタムコンテンツを追加できますが、完全に自分で実装する必要があります。)しかし、考えてみると、これは非常に合理的で一般的な練習です。そして、サーバーのレイテンシーはほとんど無視できます。

また、アクセスできるものは限られています - ほぼリクエストオブジェクトがあります。ああ、あなたが以前にそれに気付いたことがないなら、それはトップレベルのページコンポーネントでのみ動作します。

redux connect

Redux Connectは、非常に意見の高いサーバー側のレンダラーです。このパッケージには多くのコンテンツがありますが、非常に複雑で、React Router V4にアップグレードされていません。多くの設定がありますが、いくつかのレッスンを学ぶためだけに、最も重要な部分を見てみましょう:

<code class="language-javascript">ReactDOM.render(
  <provider> store={store}></provider>
    <browserrouter></browserrouter>
      <app></app>
    >
  >
, document.getElementById('root')
)</code>

デコレーターはJavaScriptでは標準ではありません。執筆時点では、フェーズ2にあるので、注意して使用してください。これは、高次コンポーネントを追加するもう1つの方法です。アイデアは単純です。キーはあなたの小道具に渡されるものであり、それからあなたは一連の約束を解析して渡すことです。これはよさそうだ。たぶん別のオプションはこれです:

<code class="language-javascript">import React from 'react'
export default class extends React.Component {
  static async getInitialProps ({ req }) {
    return req
      ? { userAgent: req.headers['user-agent'] }
      : { userAgent: navigator.userAgent }
  }
  render () {
    return <div>
      Hello World {this.props.userAgent}
    </div>
  }
}</code>

これは、あまり多くの問題なくJavaScriptで実行できます。

react-frontload

React-Frontloadリポジトリには多くのドキュメントや説明がありませんが、私が得ることができる最良の理解は、テスト(このような)とソースコードの読み取りから来るかもしれません。何かがマウントされると、それは約束のキューに追加され、キューが解析されると、それは提供されます。それがすることは非常に良いですが、十分に文書化されていない、維持、使用されていないものを推奨することは困難です。

<code class="language-javascript">// 1. 连接您的数据,类似于 react-redux @connect
@asyncConnect([{
  key: 'lunch',
  promise: ({ params, helpers }) => Promise.resolve({ id: 1, name: 'Borsch' })
}])
class App extends React.Component {
  render() {
    // 2. 将数据作为 props 访问
    const lunch = this.props.lunch
    return (
      <div>{lunch.name}</div>
    )
  }
}</code>

より良いソリューションを探しています

上記のソリューションはどれも、ライブラリの柔軟性とシンプルさに対する私の期待に本当に適合していないので、私は自分の実装を紹介します。目標は、パッケージを書くことではなく、ユースケースに基づいて独自のパッケージを書く方法のアイデアを提供することです。

この例ソリューションのリポジトリはここにあります。

理論

その背後にあるアイデアは比較的簡単ですが、最終的にはかなり多くのコードが生成されます。これは、私たちが議論しているアイデアを概説することです。

サーバーはReactコードを2回レンダリングする必要があり、これには

のみを使用します。第1レンダリングと2番目のレンダリングの間のコンテキストを維持したいと考えています。最初のレンダリングでは、API呼び出し、約束、および非同期操作を排除しようとしました。 2回目のレンダリングでは、取得したすべてのデータを取得してコンテキストに戻し、ワーキングページを配布用にレンダリングしたいと考えています。これはまた、アプリケーションコードがコンテキストに基づいてアクションを実行する必要があることを意味します(またはサーバー上またはブラウザ上にあるかなど、データがフェッチされているかどうかなど、コンテキストに基づいて操作を実行しません)。 renderToString さらに、必要に応じてカスタマイズできます。この場合、コンテキストに従ってステータスコードとヘッダーを変更します。

最初のレンダリング

コードでは、サーバーで作業しているのかブラウザで作業しているのかを知る必要があります。理想的には、それを複雑に制御する必要があります。 React Routerを使用すると、静的コンテキストプロップを取得できます。これは素晴らしいことですので、使用します。現在、next.jsから学んだように、データオブジェクトを追加してデータを要求するだけです。 APIはサーバーとクライアントの間で異なるため、クライアントAPIと同様のインターフェイスを持つことをお勧めするサーバーAPIを提供する必要があります。

<code class="language-javascript">ReactDOM.render(
  <provider> store={store}></provider>
    <browserrouter></browserrouter>
      <app></app>
    >
  >
, document.getElementById('root')
)</code>
2番目のレンダリング

最初のレンダリングの後、これらの保留中の約束を受け取り、これらの約束が完了し、再レンダリングしてコンテキストを更新するのを待ちます:

<code class="language-javascript">import React from 'react'
export default class extends React.Component {
  static async getInitialProps ({ req }) {
    return req
      ? { userAgent: req.headers['user-agent'] }
      : { userAgent: navigator.userAgent }
  }
  render () {
    return <div>
      Hello World {this.props.userAgent}
    </div>
  }
}</code>
app

サーバーからアプリケーションへのすばやくジャンプしてください:ルーター接続を備えたコンポーネントのいずれかで、今すぐ入手できます:

<code class="language-javascript">// 1. 连接您的数据,类似于 react-redux @connect
@asyncConnect([{
  key: 'lunch',
  promise: ({ params, helpers }) => Promise.resolve({ id: 1, name: 'Borsch' })
}])
class App extends React.Component {
  render() {
    // 2. 将数据作为 props 访问
    const lunch = this.props.lunch
    return (
      <div>{lunch.name}</div>
    )
  }
}</code>
すごい、複雑なコードがたくさんあります。この段階では、データフェッチコードを別のコンポーネントに分離する場所で、よりリレーしたアプローチを取ることができます。

このコンポーネントは、慣れ親しんでいるコンポーネントで構成されています - レンダリングステップと

ステップ。 4段階のステートメントが異なる状態を処理する場合、侵入、ポストフェッチ、プリレンダー、バックエンドのレンダリング。また、データを読み込んだ後、データをヘッダーに追加します。

componentWillMount最後に、データを取得する別のステップがあります。理想的には、APIとデータベースには同じAPIがあり、実行が同じになります。これらをよりスケーラブルにするために、これらをサンクまたはサガにアクションに入れたいかもしれません。

詳細については、「サーバーReactレンダリング」とリポジトリReact Serverレンダリングを表示します。データがロードされていない状態を処理する必要があることを忘れないでください!最初のロードの場合にのみサーバー側のレンダリングを行うため、後続のページにロード画面が表示されます。

index.htmlを変更してデータを追加します

ページリクエストの一部としてプリフェッチされたデータを送信する必要があるため、スクリプトタグを追加します:

service
<code class="language-javascript">@asyncConnect([{
  lunch: ({ params, helpers }) => Promise.resolve({ id: 1, name: 'Borsch' })
}])</code>

その後、検索と交換に追加する必要があります。ただし、HTMLは非常に基本的なスクリプトタグファインダーを使用するため、スクリプトタグがある場合は、ベース64エンコードする必要があります。また、私たちの頭のラベルを忘れないでください!

また、ステータスコードの変更(たとえば、404の場合)も処理します。したがって、404ページがある場合は、これを行うことができます。

<code class="language-javascript">const App = () => (
  <frontload>isServer</frontload>
    <component1> entityId='1' store={store}></component1>
  >
)

return frontloadServerRender(() => (
  render(<app></app>)
)).then((serverRenderedMarkup) => {
  console.log(serverRenderedMarkup)
})</code>

概要

<code class="language-javascript">const context = {data: {}, head: [], req, api}
const store = configureStore()
renderToString(
  <provider> store={store}></provider>
    <staticrouter> location={req.url} context={context}>
      <app></app>
    >
  >
)</staticrouter></code>

あなたが何をしているのかわからない場合は、next.jsを使用してください。サーバー側のレンダリングとユニバーサルアプリケーション向けに設計されています。または、すべてを手動で実行できる柔軟性が必要な場合は、必要な方法で実行できます。例としては、ページレベルではなく、子コンポーネントでデータを取得するデータを実行することが含まれます。 この記事があなたが始めるのに役立つことを願っています!実行可能な実装については、githubリポジトリをチェックすることを忘れないでください。

非同期APIおよびサーバー側のレンダリングReact

についての

FAQ(FAQS)

Reactでのサーバー側のレンダリングとクライアント側のレンダリングの違いは何ですか?

サーバー側のレンダリング(SSR)とクライアント側のレンダリング(CSR)は、Webページをレンダリングする2つの異なる方法です。 SSRでは、サーバーはリクエストに応じてページの完全なHTMLを生成し、クライアントに送信します。これにより、初期ページの読み込み時間が短くなり、SEOにとって有益です。ただし、各リクエストでページ全体をレンダリングする必要があるため、これによりページ変換が遅くなる可能性があります。一方、CSRは、JavaScriptを使用してブラウザでレンダリングが行われることを意味します。これにより、最初のページの読み込み時間が遅くなりますが、必要なコンポーネントのみを再レンダリングする必要があるため、ページ変換はより速くなります。

クライアントがレンダリングされたReactアプリケーションでサーバー側のリクエストを作成する方法は?

クライアント側のレンダリングされたReactアプリケーションでサーバー側のリクエストを行うには、Fetch APIやAxiosなどのライブラリを使用できます。関数コンポーネントを使用するときに、componentDidMountライフサイクルメソッドまたはuseEffectフックでリクエストを行うことができます。その後、応答は状態に設定し、コンポーネントに使用できます。

なぜ私のグローバル変数は反応で2回実行されているのですか?

これは、反応バッチ状態の更新方法による可能性があります。 Reactコンポーネント内のグローバル変数を更新すると、setStateの非同期性のために2回更新される場合があります。これを回避するために、setStateの関数形式を使用できます。これにより、状態の更新が現在の状態ではなく前の状態に基づいていることが保証されます。

サーバー側のレンダリングされたReactで非同期APIを使用する方法は?

サーバー側のレンダリングされたReactで非同期APIを使用するには、サーバー側のコードでasync/await構文を使用できます。これにより、ページをレンダリングする前にAPI応答を待つことができます。 Axiosなどのライブラリを使用して、API要求を行うことができます。

Reactでのサーバー側のレンダリングの利点は何ですか?

サーバー側のレンダリングには、Reactに多くの利点があります。初期ページの読み込み時間が改善され、ユーザーエクスペリエンスが向上する可能性があります。また、検索エンジンクローラーがサーバー側のレンダリングコンテンツをより簡単にインデックスできるため、SEOが改善されます。さらに、サーバーとクライアントの両方で同じコードが実行されるため、より一貫した初期状態が可能になります。

サーバーレンダリングReactで非同期APIを使用する場合のエラーを処理する方法は?

try/catchブロックを使用して、非同期関数のエラーを処理できます。これにより、APIリクエストを作成するときに発生するエラーをキャプチャし、エラーメッセージをレンダリングするなど、適切に処理できます。

サーバー側のレンダリングされたReactでフックを使用できますか?

はい、サーバーレンダリングReactでフックを使用できます。ただし、フックはクラスコンポーネントではなく、関数コンポーネントでのみ使用できることを忘れないでください。また、一部のフック(例:useEffect)はサーバーで実行されないため、コードがこの状況を処理できることを確認する必要があります。

サーバー側のレンダリングされたReactアプリケーションのパフォーマンスを改善する方法は?

サーバーレンダリングのReactアプリケーションのパフォーマンスを改善する方法はたくさんあります。コードセグメンテーションを使用して、各ページに必要なコードのみをロードできます。キャッシュを使用して、変更されていないページの再レンダリングを避けることもできます。さらに、サーバー側のコードを最適化すると、パフォーマンスの向上に役立ちます。

サーバー側のレンダリングされたReactアプリケーションをテストする方法は?

JestやReact Testing Libraryなどのテストライブラリを使用して、サーバー側のレンダリングされたReactアプリケーションをテストできます。これらのライブラリを使用すると、テストコンポーネントを分離し、正しくレンダリングすることを確認できます。

next.jsでサーバーレンダリングを使用できますか?

はい、next.jsは、ボックスからレンダリングするサーバー側をサポートするReactのフレームワークです。シンプルなサーバー側のレンダリングAPIを提供し、静的サイトの生成とクライアントレンダリングもサポートします。

以上がサーバーレンダリングの反応で非同期APIを扱うの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。