React实践-SSR

48 阅读1分钟

基础

  • renderToString:是用于服务器端渲染(SSR)React 应用程序的代码片段。它是 React 库中的一个模块,用于将 React 组件渲染为字符串,以便在服务器上生成 HTML,从而实现服务器端渲染。
  • hydrate:是用于在客户端进行混合的 React 库模块。在使用服务器端渲染(SSR)生成的 HTML 页面中,通过 hydrate 函数可以将客户端渲染(CSR)所需的事件处理程序和状态绑定到已经存在的 DOM 上,从而实现服务器端渲染与客户端交互的无缝切换。

实践

app.js


import express from 'express'
import path from 'path'
import template from './src/template'
import ssr from './src/server'
import data from './assets/data.json'

const app = express()

// 设置静态资源目录
app.use('/assets', express.static(path.resolve(__dirname, 'assets')))
app.use('/media', express.static(path.resolve(__dirname, 'media')))

// 禁用 x-powered-by 标头,增强应用程序的安全性
app.disable('x-powered-by')
// 启动服务
app.listen(process.env.PORT || 3000)

// 初始化数据
let initialState = {
  isFetching: false,
  apps: data
}

// 请求
app.get('/', (req, res) => {
  const { preloadedState, content}  = ssr(initialState)
  const response = template("Server Rendered Page", preloadedState, content)
  res.setHeader('Cache-Control', 'assets, max-age=604800')
  res.send(response);
});

app.get('/client', (req, res) => {
  let response = template('Client Side Rendered page')
  res.setHeader('Cache-Control', 'assets, max-age=604800')
  res.send(response)
});

server.js

import React from 'react'
import { renderToString } from 'react-dom/server'
import { Provider } from 'react-redux'
import configureStore from './redux/configureStore'
import App from './components/app'


module.exports = function render(initialState) {
  // 生成redux
  const store = configureStore(initialState)

  // 生成App
  let content = renderToString(
    <Provider store={store} >
       <App />
    </Provider>
  );

  // 获取数据
  const preloadedState = store.getState()

  return {content, preloadedState};
}

template.js

// 生成html
export default function template(title, initialState = {}, content = "") {
  let scripts = ''
  if (content) {
    scripts = ` <script>
                   window.__STATE__ = ${JSON.stringify(initialState)}
                </script>
                <script src="assets/client.js"></script>
                `
  } else {
    scripts = ` <script src="assets/bundle.js"> </script> `
  }
  let page = `<!DOCTYPE html>
              <html lang="en">
              <head>
                <meta charset="utf-8">
                <title> ${title} </title>
                <link rel="stylesheet" href="assets/style.css">
              </head>
              <body>
                <div class="content">
                   <div id="app" class="wrap-inner">
                      ${content}
                   </div>
                </div>

                  ${scripts}
              </body>
              `

  return page
}

client.js

// SSR 架构下浏览器端脚本
import React from 'react'
import {hydrate} from 'react-dom'
import {Provider} from 'react-redux'
import configureStore from './redux/configureStore'
import App from './components/app'

const state = window.__STATE__;

delete window.__STATE__;

const store = configureStore(state)

// hydrate 方法通常与服务器端渲染(SSR)一起使用,确保客户端渲染的内容与服务器端生成的内容一致
hydrate(
  <Provider store={store} >
     <App />
  </Provider>,
  document.querySelector('#app')
)