image
同構,就是一套React代碼在伺服器上運作一遍,到達浏覽器又運作一遍。服務端渲染完成頁面結構,浏覽器端渲染完成事件綁定。
那如何進行浏覽器端的事件綁定呢?
唯一的方式就是讓浏覽器去拉取JS檔案執行,讓JS代碼來控制。
image
更詳細的步驟如下:
image
下面,我們基于KOA架構講解如何做同構?
第一步:在服務端建構初始 store
擴充 Koa 的路由檔案:
// server-side ./routes/index.jsx
import Router from 'koa-router';
import { renderToString } from 'react-dom/server';
import { StaticRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux'
const router = Router();
router.get('*', async (ctx) => {
// 在服務端初始化 store 的資料
const store = createStore(state => state, {
name: 'Pspgbhu',
site: 'http://pspgbhu.me',
});
const context = {};
const content = (
{}
);
// 擷取 store 資料對象
const preloadedState = store.getState();
await ctx.render('index', {
html: content,
state: preloadedState, // 将 store 資料傳遞給 ejs 模闆引擎
});
});
export default router;
第二步:模闆引擎将初始的 store 渲染到頁面中
模闆引擎将 koa router 傳來的 store 資料指派給 window._INITIAL_STATE 對象下。
React Isomorphic
// 将服務端的 store 對象指派給該變量
window.__INITIAL_STATE_ = ;
第三步:用戶端擷取 Redux store 的初始值
// client-side index.jsx
import React from 'react';
import { hydrate } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import App from '../common/App';
// 通過服務端注入的全局變量得到初始的 state
const preloadedState = window.__INITIAL_STATE_;
const store = createStore(state => state, preloadedState);
hydrate(
,
document.querySelector('#app'),
);
同構的優缺點如下。
優點:
減少首次渲染時間
SEO
缺點:
使用 SSR 這種技術,将使原本簡單的 React 項目變得非常複雜,項目的可維護性會降低,代碼問題的追溯也會變得困難。