如何搭建一个 React SSR 应用

上一篇文章我们写了一个 React 的开发服务器, 本篇我们会在上一篇的基础上加入 SSR 功能.

一个单纯的 React 应用, 当用户访问其网站的时候, 服务器返回给用户的是一个没有"内容"的 html 文件, html 文件里只会包含一个 js 文件(即 React 打包出来的 js 文件), 而页面的具体内容是通过这个 js 文件渲染出来的.

<html>
  <head>
  ...
  </head>
  <body>
    <div id="root"></div>
    <script src="./index.js"></script>
  </body>
</html>

这种做法对于一些后台应用来说没什么问题, 但是对于前台应用来说就会有一些问题, 比如没法做搜索引擎优化, 因为搜索引擎"看"不到这个网站中的内容.

所以就有了 SSR 服务端渲染. SSR 应用 和 单纯的 React 应用相比, 当访问其网站时, 服务器返回给用户的 html 文件中不仅包含 js 文件还会包含页面的"内容".

<html>
  <head>
  ...
  </head>
  <body>
    <div id="root">
       内容...
    </div>
    <script src="./index.js"></script>
  </body>
</html>

如何让服务器返回页面的内容呢? 对于上一篇中的开发服务器来说, 相当于给 express 应用增加了一个中间件(middleware). 中间件会根据访问的路径来返回相应的内容.

// 增加一个中间件, 返回 ssr 的内容, 仅用于演示
app.use((req, res, next) => {
    const { path } = req

    if (path === '/about') {
        res.end("<body>SSR Content For <strong>ABOUT PAGE</strong><body/>");
        return;
    } 
    
    if (path === '/') {
         res.end("<body>SSR Content For <strong>HOME PAGE</strong></body>");
        return;
    }

    next()
})

只不过我们要把这个内容换成真正的 React-Router 匹配到的内容.

要得到 React-Router 匹配到的内容, 可以使用 react-router-dom/server 提供的 StaticRouter 组件. 然后通过 ReactDOMServer.renderToString 方法将 React 组件转化成字符串.

hydration 水合
点击上一个例子中的 to about 链接切换到 about 页面, 在 about 页面中点击按钮看看会发生什么?

点击按钮失效了! 点击的次数根本没有累加.

这是因为服务器只返回了 html 片段, 里面并没有 js 文件来使点击事件生效.

这就需要用到 hydration 水合, 即服务器同时生成一段 js 文件给客户端, 让 js 跟 html 片段相结合, 让这些事件都生效.

有几点需要注意的是:

  1. 需要设置几个静态文件夹, 用来返回静态文件.
    app.use(express.static(path.join(__dirname, 'public')));
    app.use('/serverDist', express.static(path.join(__dirname, 'serverDist')))
    app.use('/clientDist', express.static(path.join(__dirname, 'clientDist')))
    
  2. 在水合的时候, 装载的容器需要和服务器返回的 html 片段相一致.
    hydrateRoot(
     document.documentElement,
     <BrowserRouter>
       <App />
     </BrowserRouter>
     );
    
    因为水合的时候容器用的 document.documentElement, 所以 App 组件内返回的是 html 以内的内容.
    export default function App() {
     return (
       <>
         <head>
           <meta charSet="UTF-8" />
           <link rel="icon" type="image/x-icon" href="/favicon.svg" />
           <title>演示 SSR</title>
         </head>
         <body>
           <Routes />
           <script src='/clientDist/client.bundle.js' />
         </body>
       </>
     )
    }
    

以上就是一个基础的 SSR 应用, 这是理解 SSR 的一个很好的开始.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值