中文字幕第五页-中文字幕第页-中文字幕韩国-中文字幕最新-国产尤物二区三区在线观看-国产尤物福利视频一区二区

基于React.js和Node.js怎么實現SSR-創新互聯

這篇文章主要介紹基于React.js和Node.js怎么實現SSR,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!

網站設計、成都做網站過程中,需要針對客戶的行業特點、產品特性、目標受眾和市場情況進行定位分析,以確定網站的風格、色彩、版式、交互等方面的設計方向。成都創新互聯還需要根據客戶的需求進行功能模塊的開發和設計,包括內容管理、前臺展示、用戶權限管理、數據統計和安全保護等功能。

基礎概念

SSR:即服務端渲染(Server Side Render) 傳統的服務端渲染可以使用Java,php 等開發語言來實現,隨著 Node.js 和相關前端領域技術的不斷進步,前端同學也可以基于此完成獨立的服務端渲染。

過程:瀏覽器發送請求 -> 服務器運行 react代碼生成頁面 -> 服務器返回頁面 -> 瀏覽器下載HTML文檔 -> 頁面準備就緒 即:當前頁面的內容是服務器生成好給到瀏覽器的。

基于React.js和Node.js怎么實現SSR

對應CSR:即客戶端渲染(Client Side Render) 過程:瀏覽器發送請求 -> 服務器返回空白 HTML(HTML里包含一個root節點和js文件) -> 瀏覽器下載js文件 -> 瀏覽器運行react代碼 -> 頁面準備就緒 即:當前頁面的內容是js渲染出來

基于React.js和Node.js怎么實現SSR

如何區分頁面是否服務端渲染: 右鍵點擊 -> 顯示網頁源代碼,如果頁面上的內容在HTML文檔里,是服務端渲染,否則就是客戶端渲染。

對比

  • CSR:首屏渲染時間長,react代碼運行在瀏覽器,消耗的是瀏覽器的性能

  • SSR:首屏渲染時間短,react代碼運行在服務器,消耗的是服務器的性能

為什么要用服務端渲染

首屏加載時間優化,由于SSR是直接返回生成好內容的HTML,而普通的CSR是先返回空白的HTML,再由瀏覽器動態加載JavaScript腳本并渲染好后頁面才有內容;所以SSR首屏加載更快、減少白屏的時間、用戶體驗更好。

SEO (搜索引擎優化),搜索關鍵詞的時候排名,對大多數搜索引擎,不識別JavaScript 內容,只識別 HTML 內容。 (注:原則上可以不用服務端渲染時最好不用,所以如果只有 SEO 要求,可以用預渲染等技術去替代)

構建一個服務端渲染的項目

(1) 使用 Node.js 作為服務端和客戶端的中間層,承擔 proxy代理,處理cookie等操作。

(2) hydrate 的使用:在有服務端渲染情況下,使用hydrate代替render,它的作用主要是將相關的事件注水進HTML頁面中(即:讓React組件的數據隨著HTML文檔一起傳遞給瀏覽器網頁),這樣可以保持服務端數據和瀏覽器端一致,避免閃屏,使第一次加載體驗更高效流暢。

 ReactDom.hydrate(<App />, document.getElementById('root'));

(3) 服務端代碼webpack編譯:通常會建一個webpack.server.js文件,除了常規的參數配置外,還需要設置target參數為'node'。

const serverConfig = {
 target: 'node',
 entry: './src/server/index.js',
 output: {
 filename: 'bundle.js',
 path: path.resolve(__dirname, '../dist')
 },
 externals: [nodeExternals()],
 module: {
 rules: [{
  test: /\.js?$/,
  loader: 'babel-loader',
  exclude: [
  path.join(__dirname, './node_modules')
  ]
 }
 ...
 ]
 }
 (此處省略樣式打包,代碼壓縮,運行壞境配置等等...)
 ...
};

(4) 使用react-dom/server下的 renderToString方法在服務器上把各種復雜的組件和代碼轉化成 HTML 字符串返回到瀏覽器,并在初始請求時發送標記以加快頁面加載速度,并允許搜索引擎抓取頁面以實現SEO目的。

const render = (store, routes, req, context) => {
 const content = renderToString((
 <Provider store={store}>
  <StaticRouter location={req.path} context={context}>
  <div>
   {renderRoutes(routes)}
  </div>
  </StaticRouter>
 </Provider>
 ));
 return `
 <html>
  <head>
  <title>ssr</title>
  </head>
  <body>
  <div id='root'>${content}</div>
  <script src='/index.js'></script>
  </body>
 </html>
 `;
}
app.get('*', function (req, res) {
 ...
 const html = render(store, routes, req, context);
 res.send(html);
});

與renderToString類似功能的還有: i. renderToStaticMarkup:區別在于renderToStaticMarkup 渲染出的是不帶data-reactid的純HTML,在JavaScript加載完成后因為不認識之前服務端渲染的內容導致重新渲染(可能頁面會閃一下)。

ii. renderToNodeStream:將React元素渲染為其初始HTML,返回一個輸出HTML字符串的可讀流。

iii. renderToStaticNodeStream:與renderToNodeStream此類似,除了這不會創建React在內部使用的額外DOM屬性,例如data-reactroot。

(5) 使用redux 承擔數據準備,狀態維護的職責,通常搭配react-redux, redux-thunk(中間件:發異步請求用到action)使用。(本猿目前使用比較多是就是Redux和Mobx,這里以Redux為例)。 A. 創建store(服務器每次請求都要創建一次,客戶端只創建一次):

const reducer = combineReducers({
 home: homeReducer,
 page1: page1Reducer,
 page2: page2Reducer
});

export const getStore = (req) => {
 return createStore(reducer, applyMiddleware(thunk.withExtraArgument(serverAxios(req))));
}

export const getClientStore = () => {
 return createStore(reducer, window.STATE_FROM_SERVER, applyMiddleware(thunk.withExtraArgument(clientAxios)));
}

B. action: 負責把數據從應用傳到store,是store數據的唯一來源

export const getData = () => {
 return (dispatch, getState, axiosInstance) => {
 return axiosInstance.get('interfaceUrl/xxx')
  .then((res) => {
  dispatch({
   type: 'HOME_LIST',
   list: res.list
  })
  });
 }
}

C. reducer:接收舊的state和action,返回新的state,響應actions并發送到store。

export default (state = { list: [] }, action) => {
 switch(action.type) {
 case 'HOME_LIST':
  return {
  ...state,
  list: action.list
  }
 default:
  return state;
 }
}
export default (state = { list: [] }, action) => {
 switch(action.type) {
 case 'HOME_LIST':
  return {
  ...state,
  list: action.list
  }
 default:
  return state;
 }
}

D. 使用react-redux的connect,Provider把組件和store連接起來

Provider 將之前創建的store作為prop傳給Provider

const content = renderToString((
 <Provider store={store}>
 <StaticRouter location={req.path} context={context}>
  <div>
  {renderRoutes(routes)}
  </div>
 </StaticRouter>
 </Provider>
));

connect([mapStateToProps],[mapDispatchToProps],[mergeProps], [options])接收四個參數 常用的是前兩個屬性 mapStateToProps函數允許我們將store中的數據作為props綁定到組件上mapDispatchToProps將action作為props綁定到組件上

 connect(mapStateToProps(),mapDispatchToProps())(MyComponent)

(6) 使用react-router承擔路由職責 服務端路由不同于客戶端,它是無狀態的。React 提供了一個無狀態的組件StaticRouter,向StaticRouter傳遞當前URL,調用ReactDOMServer.renderToString() 就能匹配到路由視圖。

服務端

import { StaticRouter } from 'react-router-dom';
import { renderRoutes } from 'react-router-config'
import routes from './router.js'

<StaticRouter location={req.path} context={{context}}>
{renderRoutes(routes)}
</StaticRouter>

瀏覽器端

import { BrowserRouter } from 'react-router-dom';
import { renderRoutes } from 'react-router-config'
import routes from './router.js'

<BrowserRouter>
 {renderRoutes(routes)}
</BrowserRouter>

當瀏覽器的地址欄發生變化的時候,前端會去匹配路由視圖,同時由于req.path發生變化,服務端匹配到路由視圖,這樣保持了前后端路由視圖的一致,在頁面刷新時,仍然可以正常顯示當前視圖。如果只有瀏覽器端路由,而且是采用BrowserRouter,當頁面地址發生變化后去刷新頁面時,由于沒有對應的HTML,會導致頁面找不到,但是加了服務端路由后,刷新發生時服務端會返回一個完整的html給客戶端,頁面仍然正常顯示。 推薦使用 react-router-config插件,然后如上代碼在StaticRouter和BrowserRouter標簽的子元素里加renderRoutes(routes):建一個router.js文件

const routes = [{ component: Root,
 routes: [
 { path: '/',
  exact: true,
  component: Home,
  loadData: Home.loadData
 },
 { path: '/child/:id',
  component: Child,
  loadData: Child.loadData
  routes: [
  path: '/child/:id/grand-child',
  component: GrandChild,
  loadData: GrandChild.loadData
  ]
 }
 ]
}];

在瀏覽器端請求一個地址的時候,server.js 里在實際渲染前可以通過matchRouters 這種方式確定要渲染的內容,調用loaderData函數進行action派發,返回promise->promiseAll->renderToString,最終生成HTML文檔返回。

import { matchRoutes } from 'react-router-config'
 const loadBranchData = (location) => {
 const branch = matchRoutes(routes, location.pathname)

 const promises = branch.map(({ route, match }) => {
  return route.loadData
  ? route.loadData(match)
  : Promise.resolve(null)
 })

 return Promise.all(promises)
}

(7) 寫組件注意代碼同構(即:一套React代碼在服務端執行一次,在客戶端再執行一次) 由于服務器端綁定事件是無效的,所以服務器返回的只有頁面樣式(&注水的數據),同時返回JavaScript文件,在瀏覽器上下載并執行JavaScript時才能把事件綁上,而我們希望這個過程只需編寫一次代碼,這個時候就會用到同構,服務端渲染出樣式,在客戶端執行時綁上事件。

優點: 共用前端代碼,節省開發時間 弊端: 由于服務器端和瀏覽器環境差異,會帶來一些問題,如document等對象找不到,DOM計算報錯,前端渲染和服務端渲染內容不一致等;前端可以做非常復雜的請求合并和延遲處理,但為了同構,所有這些請求都在預先拿到結果才會渲染。

以上是“基于React.js和Node.js怎么實現SSR”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注創新互聯行業資訊頻道!

當前題目:基于React.js和Node.js怎么實現SSR-創新互聯
鏈接URL:http://www.2m8n56k.cn/article18/gssgp.html

成都網站建設公司_創新互聯,為您提供關鍵詞優化軟件開發網站制作App設計響應式網站移動網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:[email protected]。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

網站托管運營
主站蜘蛛池模板: jul-179在线中文字幕 | 免费观看欧美精品成人毛片能看的 | 日韩午夜在线观看 | 成人在线毛片 | 99久久免费午夜国产精品 | 欧美亚洲另类在线 | 中文字幕免费在线视频 | 亚洲天堂色视频 | 69精品免费视频 | 日本在线免费视频 | 亚欧成人中文字幕一区 | 色黄网站aaaaaa级毛片 | 一级特黄aa大片欧美 | 99精品一区二区免费视频 | 亚洲欧美激情精品一区二区 | 欧美va在线播放免费观看 | 国产高清在线精品一区a | 成人免费在线播放视频 | 中国美女一级黄色片 | 99在线观看精品 | 怡红院视频在线观看 | 中国国产一国产一级毛片视频 | 国产手机精品a | 亚洲成a人片在线观看中文 亚洲成a人片在线观看中文!!! | 视频一区在线免费观看 | 欧美成人资源 | 久草视频免费播放 | 精品免费视频 | 欧美色欧美亚洲高清在线视频 | 一级a爰片久久毛片 | 老司机深夜影院入口aaaa | 亚洲社区在线 | 亚洲国产日韩a在线亚洲 | 国产精品观看在线亚洲人成网 | 在线视频一区二区三区四区 | 中文在线三级中文字幕 | 99精彩视频在线观看 | 欧美一二区视频 | 久久怡红院 | 看一级特黄a大片日本片 | 成年人在线观看免费 |