<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        怎樣高效的使用React服務器端渲染

        來源:懂視網 責編:小采 時間:2020-11-27 19:47:46
        文檔

        怎樣高效的使用React服務器端渲染

        怎樣高效的使用React服務器端渲染:這次給大家帶來怎樣高效的使用React服務器端渲染,使用React服務器端渲染的注意事項有哪些,下面就是實戰案例,一起來看一下。React 提供了兩個方法 renderToString 和 renderToStaticMarkup 用來將組件(Virtual DOM)輸出成 HTML 字符串,
        推薦度:
        導讀怎樣高效的使用React服務器端渲染:這次給大家帶來怎樣高效的使用React服務器端渲染,使用React服務器端渲染的注意事項有哪些,下面就是實戰案例,一起來看一下。React 提供了兩個方法 renderToString 和 renderToStaticMarkup 用來將組件(Virtual DOM)輸出成 HTML 字符串,

        這次給大家帶來怎樣高效的使用React服務器端渲染,使用React服務器端渲染的注意事項有哪些,下面就是實戰案例,一起來看一下。

        React 提供了兩個方法 renderToString 和 renderToStaticMarkup 用來將組件(Virtual DOM)輸出成 HTML 字符串,這是 React 服務器端渲染的基礎,它移除了服務器端對于瀏覽器環境的依賴,所以讓服務器端渲染變成了一件有吸引力的事情。

        服務器端渲染除了要解決對瀏覽器環境的依賴,還要解決兩個問題:

        1. 前后端可以共享代碼

        2. 前后端路由可以統一處理

        React 生態提供了很多選擇方案,這里我們選用 Redux 和 react-router 來做說明。

        Redux

        Redux 提供了一套類似 Flux 的單向數據流,整個應用只維護一個 Store,以及面向函數式的特性讓它對服務器端渲染支持很友好。

        2 分鐘了解 Redux 是如何運作的

        關于 Store:

        1. 整個應用只有一個唯一的 Store

        2. Store 對應的狀態樹(State),由調用一個 reducer 函數(root reducer)生成

        3. 狀態樹上的每個字段都可以進一步由不同的 reducer 函數生成

        4. Store 包含了幾個方法比如 dispatch, getState 來處理數據流

        5. Store 的狀態樹只能由 dispatch(action) 來觸發更改

        Redux 的數據流:

        1. action 是一個包含 { type, payload } 的對象

        2. reducer 函數通過 store.dispatch(action) 觸發

        3. reducer 函數接受 (state, action) 兩個參數,返回一個新的 state

        4. reducer 函數判斷 action.type 然后處理對應的 action.payload 數據來更新狀態樹

        所以對于整個應用來說,一個 Store 就對應一個 UI 快照,服務器端渲染就簡化成了在服務器端初始化 Store,將 Store 傳入應用的根組件,針對根組件調用 renderToString 就將整個應用輸出成包含了初始化數據的 HTML。

        react-router

        react-router 通過一種聲明式的方式匹配不同路由決定在頁面上展示不同的組件,并且通過 props 將路由信息傳遞給組件使用,所以只要路由變更,props 就會變化,觸發組件 re-render。

        假設有一個很簡單的應用,只有兩個頁面,一個列表頁 /list 和一個詳情頁 /item/:id,點擊列表上的條目進入詳情頁。

        可以這樣定義路由,./routes.js

        import React from 'react';
        import { Route } from 'react-router';
        import { List, Item } from './components';
        // 無狀態(stateless)組件,一個簡單的容器,react-router 會根據 route
        // 規則匹配到的組件作為 `props.children` 傳入
        const Container = (props) => {
         return (
         <p>{props.children}</p>
         );
        };
        // route 規則:
        // - `/list` 顯示 `List` 組件
        // - `/item/:id` 顯示 `Item` 組件
        const routes = (
         <Route path="/" component={Container} >
         <Route path="list" component={List} />
         <Route path="item/:id" component={Item} />
         </Route>
        );
        export default routes;

        從這里開始,我們通過這個非常簡單的應用來解釋實現服務器端渲染前后端涉及的一些細節問題。

        Reducer

        Store 是由 reducer 產生的,所以 reducer 實際上反映了 Store 的狀態樹結構

        ./reducers/index.js

        import listReducer from './list';
        import itemReducer from './item';
        export default function rootReducer(state = {}, action) {
         return {
         list: listReducer(state.list, action),
         item: itemReducer(state.item, action)
         };
        }

        rootReducer 的 state 參數就是整個 Store 的狀態樹,狀態樹下的每個字段對應也可以有自己的reducer,所以這里引入了 listReducer 和 itemReducer,可以看到這兩個 reducer的 state 參數就只是整個狀態樹上對應的 list 和 item 字段。

        具體到 ./reducers/list.js

        const initialState = [];
        export default function listReducer(state = initialState, action) {
         switch(action.type) {
         case 'FETCH_LIST_SUCCESS': return [...action.payload];
         default: return state;
         }
        }

        list 就是一個包含 items 的簡單數組,可能類似這種結構:[{ id: 0, name: 'first item'}, {id: 1, name: 'second item'}],從 'FETCH_LIST_SUCCESS' 的 action.payload 獲得。

        然后是 ./reducers/item.js,處理獲取到的 item 數據

        const initialState = {};
        export default function listReducer(state = initialState, action) {
         switch(action.type) {
         case 'FETCH_ITEM_SUCCESS': return [...action.payload];
         default: return state;
         }
        }

        Action

        對應的應該要有兩個 action 來獲取 list 和 item,觸發 reducer 更改 Store,這里我們定義 fetchList 和 fetchItem 兩個 action。

        ./actions/index.js

        import fetch from 'isomorphic-fetch';
        export function fetchList() {
         return (dispatch) => {
         return fetch('/api/list')
         .then(res => res.json())
         .then(json => dispatch({ type: 'FETCH_LIST_SUCCESS', payload: json }));
         }
        }
        export function fetchItem(id) {
         return (dispatch) => {
         if (!id) return Promise.resolve();
         return fetch(`/api/item/${id}`)
         .then(res => res.json())
         .then(json => dispatch({ type: 'FETCH_ITEM_SUCCESS', payload: json }));
         }
        }

        isomorphic-fetch 是一個前后端通用的 Ajax 實現,前后端要共享代碼這點很重要。

        另外因為涉及到異步請求,這里的 action 用到了 thunk,也就是函數,redux 通過 thunk-middleware 來處理這類 action,把函數當作普通的 action dispatch 就好了,比如 dispatch(fetchList())

        Store

        我們用一個獨立的 ./store.js,配置(比如 Apply Middleware)生成 Store

        import { createStore } from 'redux';
        import rootReducer from './reducers';
        // Apply middleware here
        // ...
        export default function configureStore(initialState) {
         const store = createStore(rootReducer, initialState);
         return store;
        }

        react-redux

        接下來實現 <List>,<Item> 組件,然后把 redux 和 react 組件關聯起來,具體細節參見 react-redux

        ./app.js

        import React from 'react';
        import { render } from 'react-dom';
        import { Router } from 'react-router';
        import createBrowserHistory from 'history/lib/createBrowserHistory';
        import { Provider } from 'react-redux';
        import routes from './routes';
        import configureStore from './store';
        // `INITIAL_STATE` 來自服務器端渲染,下一部分細說
        const initialState = window.INITIAL_STATE;
        const store = configureStore(initialState);
        const Root = (props) => {
         return (
         <p>
         <Provider store={store}>
         <Router history={createBrowserHistory()}>
         {routes}
         </Router>
         </Provider>
         </p>
         );
        }
        render(<Root />, document.getElementById('root'));

        至此,客戶端部分結束。

        Server Rendering

        接下來的服務器端就比較簡單了,獲取數據可以調用 action,routes 在服務器端的處理參考 react-router server rendering,在服務器端用一個 match 方法將拿到的 request url 匹配到我們之前定義的 routes,解析成和客戶端一致的 props 對象傳遞給組件。

        ./server.js

        import express from 'express';
        import React from 'react';
        import { renderToString } from 'react-dom/server';
        import { RoutingContext, match } from 'react-router';
        import { Provider } from 'react-redux';
        import routes from './routes';
        import configureStore from './store';
        const app = express();
        function renderFullPage(html, initialState) {
         return `
         <!DOCTYPE html>
         <html lang="en">
         <head>
         <meta charset="UTF-8">
         </head>
         <body>
         <p id="root">
         <p>
         ${html}
         </p>
         </p>
         <script>
         window.INITIAL_STATE = ${JSON.stringify(initialState)};
         </script>
         <script src="/static/bundle.js"></script>
         </body>
         </html>
         `;
        }
        app.use((req, res) => {
         match({ routes, location: req.url }, (err, redirectLocation, renderProps) => {
         if (err) {
         res.status(500).end(`Internal Server Error ${err}`);
         } else if (redirectLocation) {
         res.redirect(redirectLocation.pathname + redirectLocation.search);
         } else if (renderProps) {
         const store = configureStore();
         const state = store.getState();
         Promise.all([
         store.dispatch(fetchList()),
         store.dispatch(fetchItem(renderProps.params.id))
         ])
         .then(() => {
         const html = renderToString(
         <Provider store={store}>
         <RoutingContext {...renderProps} />
         </Provider>
         );
         res.end(renderFullPage(html, store.getState()));
         });
         } else {
         res.status(404).end('Not found');
         }
         });
        });

        服務器端渲染部分可以直接通過共用客戶端 store.dispatch(action) 來統一獲取 Store 數據。另外注意 renderFullPage 生成的頁面 HTML 在 React 組件 mount 的部分(<p id="root">),前后端的 HTML 結構應該是一致的。然后要把 store 的狀態樹寫入一個全局變量(INITIAL_STATE),這樣客戶端初始化 render 的時候能夠校驗服務器生成的 HTML 結構,并且同步到初始化狀態,然后整個頁面被客戶端接管。

        最后關于頁面內鏈接跳轉如何處理?

        react-router 提供了一個 <Link> 組件用來替代 <a> 標簽,它負責管理瀏覽器 history,從而不是每次點擊鏈接都去請求服務器,然后可以通過綁定 onClick 事件來作其他處理。

        比如在 /list 頁面,對于每一個 item 都會用 <Link> 綁定一個 route url:/item/:id,并且綁定 onClick 去觸發 dispatch(fetchItem(id)) 獲取數據,顯示詳情頁內容。

        相信看了本文案例你已經掌握了方法,更多精彩請關注Gxl網其它相關文章!

        推薦閱讀:

        vue axios生產環境與發布環境配置不同接口地址步驟詳解

        JS計算圓周率到小數點后100位實現步驟詳解

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        怎樣高效的使用React服務器端渲染

        怎樣高效的使用React服務器端渲染:這次給大家帶來怎樣高效的使用React服務器端渲染,使用React服務器端渲染的注意事項有哪些,下面就是實戰案例,一起來看一下。React 提供了兩個方法 renderToString 和 renderToStaticMarkup 用來將組件(Virtual DOM)輸出成 HTML 字符串,
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲AV无码一区二区三区在线| 亚洲av日韩av无码黑人| 三级黄色片免费看| 内射无码专区久久亚洲| 国产成人高清亚洲一区91| 免费一级做a爰片久久毛片潮喷| 亚洲成在人线aⅴ免费毛片 | 亚洲国产一二三精品无码| 亚洲最大福利视频网站| 国产成人一区二区三区视频免费| 国产成人亚洲综合无码精品| 久久99精品视免费看| 亚洲国产精品专区| aa毛片免费全部播放完整| 亚洲精品成人无限看| 午夜精品射精入后重之免费观看| 久久久久久久亚洲Av无码| 丁香花免费高清视频完整版| 亚洲愉拍一区二区三区| 四虎影视成人永久免费观看视频 | 久久国产免费观看精品| 国产成人免费A在线视频| 美女免费精品高清毛片在线视| 久久乐国产精品亚洲综合| 无码中文字幕av免费放dvd| 亚洲专区中文字幕| 国产成人免费网站在线观看| 九九久久国产精品免费热6| 亚洲av综合av一区| 国产成人无码免费看片软件| 久久精品亚洲精品国产色婷| 免费看www视频| 国产色无码精品视频免费| 亚洲噜噜噜噜噜影院在线播放| 免费人成视频在线观看不卡| 一区二区三区在线免费看| 国产亚洲精品91| 精品亚洲麻豆1区2区3区| 国产一级高清免费观看| 一区二区在线免费观看| 美女免费精品高清毛片在线视|