ホームページ  >  記事  >  ウェブフロントエンド  >  Reactのサーバーサイドレンダリング例の詳細な説明

Reactのサーバーサイドレンダリング例の詳細な説明

零下一度
零下一度オリジナル
2017-07-02 10:12:581793ブラウズ

レンダリング時間をできるだけ速く、ページの応答速度を速くする必要がある場合、この記事では主に React のサーバーサイド レンダリングを使用します。興味のある方は学習してください。

1. はじめに なぜサーバーサイドレンダリングが必要なのでしょうか?サーバーサイドレンダリングはどのような状況で実行されますか?著者は、レンダリング時間をできるだけ速くし、ページの応答速度を速くする必要があり (利点)、ページを「オンデマンド」 (最初のロード/最初の画面) でレンダリングする必要がある場合にサーバー レンダリングが使用されると考えています。 」。サーバー側レンダリングの利点は、中間層 (ノード) がクライアントの初期データを要求し、ノードがページをレンダリングすることです。クライアント側レンダリングとサーバー側レンダリングの違いは何ですか?サーバーサイドのレンダリングはどれくらい速いですか?

2. 理由とアイデア

クライアント側のレンダリング ルート: 1. HTML をリクエストします -> 2. サーバーは HTML を返します -> 3. ブラウザは HTML 内の js/css ファイルをダウンロードします-> 4. js ファイルのダウンロード

が完了するまで待ちます -> 5. js がロードされ初期化されるまで待ちます -> 6. js コードが最終的に実行可能になり、js コードがバックエンド (ajax/fetch) -> 7. バックエンド データが返されるのを待ちます -> 8. 反応ダム (クライアント) がデータを最初から応答ページにレンダリングして完了します

サーバー側レンダリング ルート: 2. HTML をリクエストします -> 2. サーバーからデータをリクエストします (イントラネットリクエストは高速です) -> 3. サーバーの初期レンダリング (サーバーのパフォーマンスが高く、高速です) -> 4. サーバーは次のページを返します。正しいコンテンツ -> 5. クライアントが js/css ファイルを要求します - > 6. js ファイルがダウンロードされるのを待ちます -> 7. js がロードされ初期化されるのを待ちます -> 8.クライアント) は、残りの部分のレンダリングを完了します (小さなコンテンツ、高速レンダリング)

注: はい、同じコンポーネントについて、サーバーは「視覚的」部分 (コードの render/componentWillMount 部分) をレンダリングします。には完全な

ライフサイクル

イベント処理 があるため、クライアントはそれを再度レンダリングする必要があります。つまり、サーバー側のレンダリングでは、実際にはクライアントが二次レンダリングを再度実行する必要がありますが、オーバーヘッドはほとんどありません。 時間消費量の比較:

1. データリクエスト: クライアントの代わりにサーバーがデータをリクエストします。これが「高速」の主な理由の 1 つです。サーバーはイントラネット上でリクエストを行うため、データの応答速度が高速です。クライアントは異なるネットワーク環境でデータ要求を行い、外部ネットワークの http 要求はコストがかかるため、時間差が生じます (主な理由)。

2. 手順: サーバーは最初にデータをリクエストし、次に「ビジュアル」部分をレンダリングします。一方、クライアントは

js コードがダウンロードされるのを待ち、ロードが完了してからデータをリクエストしてレンダリングします。つまり、サーバー側レンダリングでは、データをリクエストする前に JS コードがダウンロードされるのを待つ必要がなく、コンテンツがすでに含まれているページが返されます。

3. レンダリング パフォーマンス: サーバーのパフォーマンスがクライアントよりも高く、レンダリング速度が速くなります (このデータは不明です)。 4. コンテンツのレンダリング: サーバー側のレンダリングでは、最初に「視覚的な」部分がレンダリングされ、それが部分的なレンダリングのためにクライアントに渡されます。クライアント側のレンダリングは最初から開始され、完全なレンダリング手順が必要になります。

3.

注意事項

と質問 0.答え: ノード側: Express、react-dom/server、webpack。フロントエンド: React、mobx (より良い redux)、React-router、webpack1. フロントエンド/ノードエンドはコードのどの部分を共有しますか?回答: ノード/フロントエンドには独自の

エントリー ファイル

、server.js/client.js があり、react-router のルーティング

設定ファイル

routes.js が中間層として使用されます

// routes.js
module.exports = (
  <Route path="/" component={ IComponent } >
    <Route path="/todo" component={ AComponent }>
    </Route>
  </Route>
)

2. コードは表と裏で構成されています。コードが両面で共有されている場合、異なるプラットフォームで異なるコードを操作するにはどうすればよいですか?回答: Webpack 経由。


 // webpack.client.config.js
plugins: [
   new webpack.DefinePlugin({
     &#39;isServer&#39;: false,
     &#39;isClient&#39;: true
   })
 ]
// webpack.server.config.js
plugins: [
   new webpack.DefinePlugin({
     &#39;isServer&#39;: true,
     &#39;isClient&#39;: false
   })
 ]
// xxx.js
if( isServer ) {
  ...
}else { ... }


を追加して、さまざまなプラットフォーム用の webpack (babel) を使用して共有コードをコンパイルします。 4. webpack.config.js のコンポーネントのライフサイクルは何ですか?答え:componentWillMount(ノード側) ->render(ノード側) ->クライアントのライフサイクルは以前と同じです

5.回答: まずノード側のデータに基づいてレンダリングし、次にそのデータをページとともにフロントエンドに返します。その後、React がデータに基づいてレンダリングと校正を実行します (フロントエンドとバックエンドのレンダリング結果が異なる場合)一貫性がない場合、エラーが報告されます)。コンポーネントは、componentWillMount でローカル データを同期できるようにする必要があります

// 组件.js
componentWillMount() {
  if( isClient ) {
     this.todoStore.todos = window.initTodos; 
  }
}  
// node端返回
`
<!doctype html>
<html lang="utf-8">
    <head>
    <script> window.initTodo = ${...}</script>
    </head>
    <body> ... </body>
    <script src="/static/vendor.js"></script>
    <script src="/static/client.bundle.js"></script>

6. 前端/node端“入口文件”通过webpack构建有什么不同?答:前端是为了解析JSX与es6代码(包括mobx的es6 decorator),node端除了以上,还需要加入babel-plugin-transform-runtime,是为了在node良好地运行es7 async / awatit

7. 如何保证node端能够先请求数据然后再渲染?答:es7的async / await语法  

8. 前端的react-router路由与node端路由如何配合?node如何知道该路由是渲染哪个数据呢?答:前端是以前的react-router配置,node端是react-router的match/RouterContext// 共享文件routes.js


const routes = (
  <Route path="/" component={ IComponent } >
    <Route path="/todo" component={ AComponent }>
    </Route>
  </Route>
)
// 前端入口文件client.js
render(
  <Router routes={ routes } history={ browserHistory } />,
  ele
)
// node端入口文件server.js
let app = express();
app.get(&#39;/todo&#39;, (req, res) => {

  match({ routes: routes, location: req.url }, async (err, redirect, props) => {
     // match会帮我们找到要渲染的组件链,注:上面一行使用了async语法,因此可以在render之前使用await运行拉取数据的代码
     let html = renderToString(<RouterContext {...props} />)
     res.send( indexPage(html) )
  }
}) 
// node端返回   
let indexPage = (html)=>{
  return `
  <!doctype html>
    <html lang="utf-8">
      <head>
        <script>
        </script>
      </head>
      <body>
        <section id="hzpapp" >${html}</section>
      </body>
      <script src="/static/vendor.js"></script>
      <script src="/static/client.bundle.js"></script>
    </html>
}

9. client.js中是否还能继续使用webpack的require.ensure ? 答:可以。但闪白明显,且node端返回html后会有报错,在加载脚本后该错误能忽略。 

10. 若我使用的是mobx,该如何实例化store ? 答:每一个node请求,都应该返回一个新的独立的store实例,而不是每个node请求共用一个store实例(笔者易犯)。

        

本demo地址( 前端库React+mobx+ReactRouter ):github.com/Penggggg/react-ssr

以上がReactのサーバーサイドレンダリング例の詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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