溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

React服務(wù)端渲染的示例分析

發(fā)布時(shí)間:2021-09-06 09:52:26 來源:億速云 閱讀:114 作者:小新 欄目:web開發(fā)

這篇文章主要介紹了React服務(wù)端渲染的示例分析,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

一、前言

為什么需要服務(wù)端渲染?什么情況下進(jìn)行服務(wù)端渲染?筆者認(rèn)為,當(dāng)我們要求渲染時(shí)間盡量快、頁(yè)面響應(yīng)速度快時(shí)(優(yōu)點(diǎn)),才會(huì)采用服務(wù)器渲染,并且應(yīng)該“按需”對(duì)頁(yè)面進(jìn)行渲染 ——“首次加載/首屏”。即服務(wù)端渲染的優(yōu)勢(shì)在于:由中間層( node端 )為客戶端請(qǐng)求初始數(shù)據(jù)、并由node渲染頁(yè)面。那客戶端渲染和服務(wù)端渲染有什么差別?服務(wù)端渲染究竟快在哪里呢?

二、原因與思路

客戶端渲染路線:1. 請(qǐng)求一個(gè)html -> 2. 服務(wù)端返回一個(gè)html -> 3. 瀏覽器下載html里面的js/css文件 -> 4. 等待js文件下載完成 -> 5. 等待js加載并初始化完成 -> 6. js代碼終于可以運(yùn)行,由js代碼向后端請(qǐng)求數(shù)據(jù)( ajax/fetch ) -> 7. 等待后端數(shù)據(jù)返回 -> 8. react-dom( 客戶端 )從無到完整地,把數(shù)據(jù)渲染為響應(yīng)頁(yè)面

服務(wù)端渲染路線:2. 請(qǐng)求一個(gè)html -> 2. 服務(wù)端請(qǐng)求數(shù)據(jù)( 內(nèi)網(wǎng)請(qǐng)求快 ) -> 3. 服務(wù)器初始渲染(服務(wù)端性能好,較快) -> 4. 服務(wù)端返回已經(jīng)有正確內(nèi)容的頁(yè)面 -> 5. 客戶端請(qǐng)求js/css文件 -> 6. 等待js文件下載完成 -> 7. 等待js加載并初始化完成 -> 8. react-dom( 客戶端 )把剩下一部分渲染完成( 內(nèi)容小,渲染快 )

說明:對(duì)同一個(gè)組件,服務(wù)端渲染“可視的”一部分( render/componentWillMount部分代碼  ),為確保組件有完善的生命周期及事件處理,客戶端需要再次渲染。即:服務(wù)端渲染,實(shí)際上也是需要客戶端進(jìn)行 再次地、但開銷很小的二次渲染。

時(shí)間耗時(shí)比較:

1. 數(shù)據(jù)請(qǐng)求:由服務(wù)端請(qǐng)求數(shù)據(jù)而不是客戶端請(qǐng)求數(shù)據(jù),這是“快”的一個(gè)主要原因。服務(wù)端在內(nèi)網(wǎng)進(jìn)行請(qǐng)求,數(shù)據(jù)響應(yīng)速度快??蛻舳嗽诓煌W(wǎng)絡(luò)環(huán)境進(jìn)行數(shù)據(jù)請(qǐng)求,且外網(wǎng)http請(qǐng)求開銷大,導(dǎo)致時(shí)間差(主要原因)。

2. 步驟:服務(wù)端是先請(qǐng)求數(shù)據(jù)然后渲染“可視”部分,而客戶端是等待js代碼下載、加載完成再請(qǐng)求數(shù)據(jù)、渲染。即:服務(wù)端渲染不用等待js代碼下載完成再請(qǐng)求數(shù)據(jù),并會(huì)返回一個(gè)已經(jīng)有內(nèi)容的頁(yè)面。

3. 渲染性能:服務(wù)端性能比客戶端高,渲染速度快( 猜測(cè),該項(xiàng)數(shù)據(jù)不詳 )。

4. 渲染內(nèi)容:服務(wù)端渲染會(huì)把”可視“部分先渲染,然后交給客戶端再作部分渲染。而客戶端渲染,則是從無到有,需要經(jīng)歷完整的渲染步驟?!   ?/p>

React服務(wù)端渲染的示例分析  

三、注意事項(xiàng)與問題

0. 項(xiàng)目依賴什么?答:node端:express、react-dom/server、webpack。前端:React、mobx(一個(gè)更好的redux)、React-router、webpack

1. 前端/node端共用那部分代碼?答:node端/前端有各自的入口文件,server.js/client.js,通過react-router的路由配置文件routes.js作中間層

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

2. 代碼是由前后端共享,那如何分平臺(tái)地操作不同代碼?答:通過webpack。對(duì)共享代碼,進(jìn)行不同平臺(tái)的,webpack(babel)編譯,通過在webpack.config.js中加入

 // webpack.client.config.js
plugins: [
   new webpack.DefinePlugin({
     '__isServer__': false,
     '__isClient__': true
   })
 ]
// webpack.server.config.js
plugins: [
   new webpack.DefinePlugin({
     '__isServer__': true,
     '__isClient__': false
   })
 ]
// xxx.js
if( __isServer__ ) {
  ...
}else { ... }

React服務(wù)端渲染的示例分析

4. 組件的生命周期是如何的呢?答:componentWillMount( node端 ) -> render( node端 ) -> 客戶端生命周期和以前一樣

5. 拉取數(shù)據(jù)后如何處理呢?答:先在node端根據(jù)數(shù)據(jù)渲染好,再把數(shù)據(jù)隨頁(yè)面返回至前端,再由React根據(jù)數(shù)據(jù)進(jìn)行渲染校對(duì)( 若前后端渲染結(jié)果不一致將報(bào)錯(cuò) )。應(yīng)該在componentWillMount讓組件進(jìn)行本地的數(shù)據(jù)同步

// 組件.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構(gòu)建有什么不同?答:前端是為了解析JSX與es6代碼(包括mobx的es6 decorator),node端除了以上,還需要加入babel-plugin-transform-runtime,是為了在node良好地運(yùn)行es7 async / awatit

7. 如何保證node端能夠先請(qǐng)求數(shù)據(jù)然后再渲染?答:es7的async / await語(yǔ)法  

8. 前端的react-router路由與node端路由如何配合?node如何知道該路由是渲染哪個(gè)數(shù)據(jù)呢?答:前端是以前的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('/todo', (req, res) => {

  match({ routes: routes, location: req.url }, async (err, redirect, props) => {
     // match會(huì)幫我們找到要渲染的組件鏈,注:上面一行使用了async語(yǔ)法,因此可以在render之前使用await運(yùn)行拉取數(shù)據(jù)的代碼
     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中是否還能繼續(xù)使用webpack的require.ensure ? 答:可以。但閃白明顯,且node端返回html后會(huì)有報(bào)錯(cuò),在加載腳本后該錯(cuò)誤能忽略?!?/p>

10. 若我使用的是mobx,該如何實(shí)例化store ? 答:每一個(gè)node請(qǐng)求,都應(yīng)該返回一個(gè)新的獨(dú)立的store實(shí)例,而不是每個(gè)node請(qǐng)求共用一個(gè)store實(shí)例(筆者易犯)。

React服務(wù)端渲染的示例分析        

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“React服務(wù)端渲染的示例分析”這篇文章對(duì)大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識(shí)等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI