ホームページ >ウェブフロントエンド >jsチュートリアル >サーバーレンダリングの反応で非同期APIを扱う
概要
サーバー側のレンダリングコードの2つの主な利点は次のとおりです。
速度を上げる速度
SEOの柔軟性の向上Reactは主にレンダリングを同期するため、データがない場合、ロード画面がレンダリングされ、データが到着するのを待ちます。レンダリングの前に必要なものがわからないか、必要なものがわかっているが、レンダリングしたため、これはサーバー側ではうまく機能しません。 この標準レンダリング方法を表示:
質問:
ここで2つのライブラリを使用していたので、非常に人気があるので、使用する他のライブラリに適用できることを願っています。
Redux:ストレージサーバーとクライアントの同期の状態は悪夢の問題です。それは非常に高価であり、多くの場合、複雑なエラーにつながります。サーバー側では、理想的には、物事を機能させて正しくレンダリングするのに十分であることを除いて、Reduxで何もしたくありません。 (通常どおり使用できます。クライアントのように見えるように十分な状態を設定するだけです。)試してみたい場合は、さまざまな分散システムガイドを出発点としてチェックしてください。
React-Router:FYI、これはV4バージョンであり、デフォルトのインストールバージョンですが、古い既存のプロジェクトがある場合は非常に異なります。サーバー側とクライアント側のルーティングを処理し、V4を使用することを確認する必要があります。この点で優れています。
結局のところ、データベース呼び出しを行う必要がある場合はどうなりますか?これは非同期であり、コンポーネントの内側にあるため、突然大きな問題になります。もちろん、これは新しい質問ではありません。公式のReactリポジトリでそれを見る。
必要な依存関係を決定するには、クライアントに提供される前にこれらの依存関係を取得するために必要な依存関係を決定する必要があります。
既存のソリューション
以下では、この問題に現在提供されているソリューションを確認します。
開始する前に、次の.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は、非常に意見の高いサーバー側のレンダラーです。このパッケージには多くのコンテンツがありますが、非常に複雑で、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リポジトリには多くのドキュメントや説明がありませんが、私が得ることができる最良の理解は、テスト(このような)とソースコードの読み取りから来るかもしれません。何かがマウントされると、それは約束のキューに追加され、キューが解析されると、それは提供されます。それがすることは非常に良いですが、十分に文書化されていない、維持、使用されていないものを推奨することは困難です。
<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>
また、ステータスコードの変更(たとえば、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)サーバー側のレンダリング(SSR)とクライアント側のレンダリング(CSR)は、Webページをレンダリングする2つの異なる方法です。 SSRでは、サーバーはリクエストに応じてページの完全なHTMLを生成し、クライアントに送信します。これにより、初期ページの読み込み時間が短くなり、SEOにとって有益です。ただし、各リクエストでページ全体をレンダリングする必要があるため、これによりページ変換が遅くなる可能性があります。一方、CSRは、JavaScriptを使用してブラウザでレンダリングが行われることを意味します。これにより、最初のページの読み込み時間が遅くなりますが、必要なコンポーネントのみを再レンダリングする必要があるため、ページ変換はより速くなります。
クライアント側のレンダリングされたReactアプリケーションでサーバー側のリクエストを行うには、Fetch APIやAxiosなどのライブラリを使用できます。関数コンポーネントを使用するときに、componentDidMount
ライフサイクルメソッドまたはuseEffect
フックでリクエストを行うことができます。その後、応答は状態に設定し、コンポーネントに使用できます。
これは、反応バッチ状態の更新方法による可能性があります。 Reactコンポーネント内のグローバル変数を更新すると、setState
の非同期性のために2回更新される場合があります。これを回避するために、setState
の関数形式を使用できます。これにより、状態の更新が現在の状態ではなく前の状態に基づいていることが保証されます。
サーバー側のレンダリングされたReactで非同期APIを使用するには、サーバー側のコードでasync/await
構文を使用できます。これにより、ページをレンダリングする前にAPI応答を待つことができます。 Axiosなどのライブラリを使用して、API要求を行うことができます。
サーバー側のレンダリングには、Reactに多くの利点があります。初期ページの読み込み時間が改善され、ユーザーエクスペリエンスが向上する可能性があります。また、検索エンジンクローラーがサーバー側のレンダリングコンテンツをより簡単にインデックスできるため、SEOが改善されます。さらに、サーバーとクライアントの両方で同じコードが実行されるため、より一貫した初期状態が可能になります。
try/catch
ブロックを使用して、非同期関数のエラーを処理できます。これにより、APIリクエストを作成するときに発生するエラーをキャプチャし、エラーメッセージをレンダリングするなど、適切に処理できます。
はい、サーバーレンダリングReactでフックを使用できます。ただし、フックはクラスコンポーネントではなく、関数コンポーネントでのみ使用できることを忘れないでください。また、一部のフック(例:useEffect
)はサーバーで実行されないため、コードがこの状況を処理できることを確認する必要があります。
サーバーレンダリングのReactアプリケーションのパフォーマンスを改善する方法はたくさんあります。コードセグメンテーションを使用して、各ページに必要なコードのみをロードできます。キャッシュを使用して、変更されていないページの再レンダリングを避けることもできます。さらに、サーバー側のコードを最適化すると、パフォーマンスの向上に役立ちます。
JestやReact Testing Libraryなどのテストライブラリを使用して、サーバー側のレンダリングされたReactアプリケーションをテストできます。これらのライブラリを使用すると、テストコンポーネントを分離し、正しくレンダリングすることを確認できます。
はい、next.jsは、ボックスからレンダリングするサーバー側をサポートするReactのフレームワークです。シンプルなサーバー側のレンダリングAPIを提供し、静的サイトの生成とクライアントレンダリングもサポートします。
以上がサーバーレンダリングの反応で非同期APIを扱うの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。