真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

React服務(wù)器端渲染怎么用

這篇文章給大家分享的是有關(guān)React服務(wù)器端渲染怎么用的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

專注于為中小企業(yè)提供成都網(wǎng)站制作、網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)永昌免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了數(shù)千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

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

服務(wù)器端渲染除了要解決對瀏覽器環(huán)境的依賴,還要解決兩個問題:

  1. 前后端可以共享代碼

  2. 前后端路由可以統(tǒng)一處理

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

Redux

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

2 分鐘了解 Redux 是如何運(yùn)作的

關(guān)于 Store:

  1. 整個應(yīng)用只有一個唯一的 Store

  2. Store 對應(yīng)的狀態(tài)樹(State),由調(diào)用一個 reducer 函數(shù)(root reducer)生成

  3. 狀態(tài)樹上的每個字段都可以進(jìn)一步由不同的 reducer 函數(shù)生成

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

  5. Store 的狀態(tài)樹只能由 dispatch(action) 來觸發(fā)更改

Redux 的數(shù)據(jù)流:

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

  2. reducer 函數(shù)通過 store.dispatch(action) 觸發(fā)

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

  4. reducer 函數(shù)判斷 action.type 然后處理對應(yīng)的 action.payload 數(shù)據(jù)來更新狀態(tài)樹

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

react-router

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

假設(shè)有一個很簡單的應(yīng)用,只有兩個頁面,一個列表頁 /list 和一個詳情頁 /item/:id,點擊列表上的條目進(jìn)入詳情頁。

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

import React from 'react';
import { Route } from 'react-router';
import { List, Item } from './components';

// 無狀態(tài)(stateless)組件,一個簡單的容器,react-router 會根據(jù) route
// 規(guī)則匹配到的組件作為 `props.children` 傳入
const Container = (props) => {
 return (
  
{props.children}
 ); }; // route 規(guī)則: // - `/list` 顯示 `List` 組件 // - `/item/:id` 顯示 `Item` 組件 const routes = (           ); export default routes;

從這里開始,我們通過這個非常簡單的應(yīng)用來解釋實現(xiàn)服務(wù)器端渲染前后端涉及的一些細(xì)節(jié)問題。

Reducer

Store 是由 reducer 產(chǎn)生的,所以 reducer 實際上反映了 Store 的狀態(tài)樹結(jié)構(gòu)

./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 參數(shù)就是整個 Store 的狀態(tài)樹,狀態(tài)樹下的每個字段對應(yīng)也可以有自己的reducer,所以這里引入了 listReducer 和 itemReducer,可以看到這兩個 reducer的 state 參數(shù)就只是整個狀態(tài)樹上對應(yīng)的 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 的簡單數(shù)組,可能類似這種結(jié)構(gòu):[{ id: 0, name: 'first item'}, {id: 1, name: 'second item'}],從 'FETCH_LIST_SUCCESS' 的 action.payload 獲得。

然后是 ./reducers/item.js,處理獲取到的 item 數(shù)據(jù)

const initialState = {};

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

Action

對應(yīng)的應(yīng)該要有兩個 action 來獲取 list 和 item,觸發(fā) 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 實現(xiàn),前后端要共享代碼這點很重要。

另外因為涉及到異步請求,這里的 action 用到了 thunk,也就是函數(shù),redux 通過 thunk-middleware 來處理這類 action,把函數(shù)當(dāng)作普通的 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

接下來實現(xiàn) 組件,然后把 redux 和 react 組件關(guān)聯(lián)起來,具體細(xì)節(jié)參見 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__` 來自服務(wù)器端渲染,下一部分細(xì)說
const initialState = window.__INITIAL_STATE__;
const store = configureStore(initialState);
const Root = (props) => {
 return (
  
              {routes}            
 ); } render(, document.getElementById('root'));

至此,客戶端部分結(jié)束。

Server Rendering

接下來的服務(wù)器端就比較簡單了,獲取數(shù)據(jù)可以調(diào)用 action,routes 在服務(wù)器端的處理參考 react-router server rendering,在服務(wù)器端用一個 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 `
  
  
  
   
  
  
   
    
     ${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(                        );     res.end(renderFullPage(html, store.getState()));    });   } else {    res.status(404).end('Not found');   }  }); });

服務(wù)器端渲染部分可以直接通過共用客戶端 store.dispatch(action) 來統(tǒng)一獲取 Store 數(shù)據(jù)。另外注意 renderFullPage 生成的頁面 HTML 在 React 組件 mount 的部分(

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部