加入收藏 | 设为首页 | 会员中心 | 我要投稿 汽车网 (https://www.0577qiche.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 教程 > 正文

Reudx 服务端渲染方法

发布时间:2023-04-07 08:44:51 所属栏目:教程 来源:
导读:服务端渲染一个很常见的场景是当用户(或搜索引擎爬虫)第一次请求页面时,用它来做初始渲染。当服务器接收到请求后,它把需要的组件渲染成 HTML 字符串,然后把它返回给客户端(这里统指浏览器)。之后,客户端会接
服务端渲染一个很常见的场景是当用户(或搜索引擎爬虫)第一次请求页面时,用它来做初始渲染。当服务器接收到请求后,它把需要的组件渲染成 HTML 字符串,然后把它返回给客户端(这里统指浏览器)。之后,客户端会接手渲染控制权。

下面我们使用 React 来做示例,对于支持服务端渲染的其它 view 框架,做法也是类似的。

服务端使用 Redux
当在服务器使用 Redux 渲染时,一定要在响应中包含应用的 state,这样客户端可以把它作为初始 state。这点至关重要,因为如果在生成 HTML 前预加载了数据,我们希望客户端也能访问这些数据。否则,客户端生成的 HTML 与服务器端返回的 HTML 就会不匹配,客户端还需要重新加载数据。

把数据发送到客户端,需要以下步骤:

为每次请求创建全新的 Redux store 实例;

按需 dispatch 一些 action;

从 store 中取出 state;

把 state 一同返回给客户端。

在客户端,使用服务器返回的 state 创建并初始化一个全新的 Redux store。
Redux 在服务端惟一要做的事情就是,提供应用所需的初始 state。

安装
下面来介绍如何配置服务端渲染。使用极简的 Counter 计数器应用 来做示例,介绍如何根据请求在服务端提前渲染 state。

安装依赖库
本例会使用 Express 来做小型的 web 服务器。还需要安装 Redux 对 React 的绑定库,Redux 默认并不包含。

npm install --save express react-redux
服务端开发
下面是服务端代码大概的样子。使用 app.use 挂载 Express middleware 处理所有请求。如果你还不熟悉 Express 或者 middleware,只需要了解每次服务器收到请求时都会调用 handleRender 函数。

另外,如果有使用 ES6 和 JSX 语法,需要使用 Babel (对应示例this example of a Node Server with Babel) 和 React preset。

server.js
import path from 'path'
import Express from 'express'
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import counterapp from './reducers'
import App from './containers/App'
 
const app = Express()
const port = 3000
 
// 提供静态文件
app.use('/static', Express.static('static'))
 
// 每当收到请求时都会触发
app.use(handleRender)
 
// 接下来会补充这部分代码
function handleRender(req, res) {
  /* ... */
}
function renderFullPage(html, preloadedState) {
  /* ... */
}
 
app.listen(port)
处理请求
第一件要做的事情就是对每个请求创建一个新的 Redux store 实例。这个 store 惟一作用是提供应用初始的 state。

渲染时,使用 <Provider> 来包住根组件 <App />,以此来让组件树中所有组件都能访问到 store,就像之前的搭配 React 教程讲的那样。

服务端渲染最关键的一步是在发送响应前渲染初始的 HTML。这就要使用 ReactDOMServer.renderToString()。

然后使用 store.getState() 从 store 得到初始 state。renderFullPage 函数会介绍接下来如何传递。

import { renderToString } from 'react-dom/server'
 
function handleRender(req, res) {
  // 创建新的 Redux store 实例
  const store = createStore(counterapp)
 
  // 把组件渲染成字符串
  const html = renderToString(
    <Provider store={store}>
      <App />
    </Provider>
  )
 
  // 从 store 中获得初始 state
  const preloadedState = store.getState()
 
  // 把渲染后的页面内容发送给客户端
  res.send(renderFullPage(html, preloadedState))
}
注入初始组件的 HTML 和 State
服务端最后一步就是把初始组件的 HTML 和初始 state 注入到客户端能够渲染的模板中。如何传递 state 呢,我们添加一个 <script> 标签来把 preloadedState 赋给 window.__PRELOADED_STATE__。

客户端可以通过 window.__PRELOADED_STATE__ 获取 preloadedState。

同时使用 script 标签来引入打包后的 js bundle 文件。这是打包工具输出的客户端入口文件,以静态文件或者 URL 的方式实现服务端开发中的热加载。下面是代码。

function renderFullPage(html, preloadedState) {
  return `
    <!doctype html>
    <html>
      <head>
        <title>Redux Universal Example</title>
      </head>
      <body>
        <div id="root">${html}</div>
        <script>
          // 警告:关于在 HTML 中嵌入 JSON 的安全问题,请查看以下文档
          // http://redux.js.org/recipes/ServerRendering.html#security-considerations
          window.__PRELOADED_STATE__ = ${JSON.stringify(preloadedState).replace(
            /</g,
            '\\u003c'
          )}
        </script>
        <script src="/static/bundle.js"></script>
      </body>
    </html>
    `
}
客户端开发
客户端代码非常直观。只需要从 window.__PRELOADED_STATE__ 得到初始 state,并传给 createStore() 函数即可。

代码如下:

client.js
import React from 'react'
import { hydrate } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './containers/App'
import counterapp from './reducers'
 
// 通过服务端注入的全局变量得到初始 state
const preloadedState = window.__PRELOADED_STATE__
 
// 使用初始 state 创建 Redux store
const store = createStore(counterapp, preloadedState)
 
hydrate(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)
你可以选择自己喜欢的打包工具(Webpack, browserify 或其它)来编译并打包文件到 static/bundle.js。

当页面加载时,打包后的 js 会启动,并调用 React.hydrate(),然后会与服务端渲染的 HTML 的 data-react-id 属性做关联。这会把新生成的 React 实例与服务端的虚拟 DOM 连接起来。因为同样使用了来自 Redux store 的初始 state,并且 view 组件代码是一样的,结果就是我们得到了相同的 DOM。

就是这样!这就是实现服务端渲染的所有步骤。

但这样做还是比较原始的。只会用动态代码渲染一个静态的 View。下一步要做的是动态创建初始 state 支持动态渲染 view。

准备初始 State
因为客户端只是执行收到的代码,刚开始的初始 state 可能是空的,然后根据需要获取 state。在服务端,渲染是同步执行的而且我们只有一次渲染 view 的机会。在收到请求时,可能需要根据请求参数或者外部 state(如访问 API 或者数据库),计算后得到初始 state。

(编辑:汽车网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章