React SSR,如何理解和使用脱水函数renderToString()?
发布于 作者:苏南大叔 来源:程序如此灵动~终于开始讲react
的脱水和注水功能了,也就是“水合”。其中的“脱水”过程,实际上也可以理解为服务器端把事件绑定之类的功能都去掉,仅仅像传统页面一样,考虑数据的输出即可。目前脱水函数,有两个。本文讲述其中第一个:renderToString()
。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的编程心得体会。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react-router-dom@6.27.0
,react@18.3.1
。值得一提的是,react
官方,目前并不推荐使用renderToString()
。
renderToString()
苏南大叔的理解就是:使用renderToString()
函数,把以往以jsx
+js
组合呈现的react
代码,“脱水”成无限接近于纯html
的字符串的过程。当然,这个最终得到的字符串,也丧失了react
的各种活性。
官方对这个函数的解释是:
官方文档里面,定义的函数原型是:
renderToString(reactNode, options?)
由于renderToString()
的执行过程,需要耗时。而且,这个函数的使用场合多发生在服务器端。为了不拖慢服务器端的代码表现,(实际上就是第一个字节到达浏览器的时间,这个重要页面指标)。官方推荐使用其它支持pipe
输出的函数,待议。
1、客户端其实也能运行renderToString()
。但是角色分类上,renderToString()
是使用在服务器端的代码。
2、options
参数,基本上也没有啥大用途。暂时无视。
引入 renderToString
在目前最新的React
中,是这样引入的。注意:/server
字样。这是和老版本最大的不同之处。
import { renderToString } from "react-dom/server";
最简单demo
这里仅仅是个最简单的demo
,和实际应用有较大差距。
import React from "react";
import { renderToString } from "react-dom/server";
const App = function () {
return <div>苏南大叔</div>;
};
const html = renderToString(<App />);
console.log(html);
搭配 http 服务输出
renderToString()
的设计之初,就是在服务器端输出无限接近纯正html
的目的的。所以,这里结合最简单的http
服务,同时搭配react router
的StaticRouter
使用。
import http from "http";
import React from "react";
import { renderToString } from "react-dom/server";
import { StaticRouter } from "react-router-dom/server";
import { Routes, Route, useParams } from "react-router-dom";
function Post() {
var { id } = useParams();
return <div>No.{id} article</div>;
}
function requestHandler(req, res) {
let html = renderToString(
<StaticRouter location={req.url}>
<Routes>
<Route path="/" element={<div>home</div>} />
<Route path="/post/:id" element={<Post />} />
</Routes>
</StaticRouter>
);
res.write(html);
res.end();
}
http.createServer(requestHandler).listen(3006);
这个例子,参考文章:
这里可以注意到:输出的就是无限接近于传统html
的代码,并没有React
程序底部标配的app.js
(或其它名字)的引用。说明,两者并不是强绑定的。
搭配 express 输出
在nodejs
的世界里面,更多的情况,是搭配express
使用的。同时搭配react router
的StaticRouter
的话,测试如下:
import express from "express";
import React from "react";
import { Routes, Route, useParams } from "react-router-dom";
import { StaticRouter } from "react-router-dom/server";
import { renderToString } from "react-dom/server";
function Post() {
var { id } = useParams();
return <div>No.{id} article</div>;
}
const app2 = express();
app2.use(express.static("dist"));
app2.get("/*", (req, res) => {
let html = renderToString(
<StaticRouter location={req.url}>
<Routes>
<Route path="/" element={<div>home</div>} />
<Route path="/post/:id" element={<Post />} />
</Routes>
</StaticRouter>
);
let data = {
www: "newsn.net",
author: "苏南大叔",
};
function template() {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>React Server Side Rendering</title>
</head>
<body>
<div id="root">${html}</div>
<script> window.__ROUTE_DATA__ = ${JSON.stringify(data)} </script>
<script src="/app.js"></script>
</body>
</html>`;
}
res.send(template());
});
app2.listen(3006);
这个代码就相对完整了,很接近实际应用中的样子。这里还带出来了用于“补水”的app.js
文件。这个文件是怎么来的,以及window.__ROUTE_DATA__
这个全局变量是怎么回事,会在后续的“补水”相关文章里面进行说明。
总结
这里可以看到,无论是普通的react
代码,还是说带着react router
的路由代码。都可以当作jsx
组件,传递给renderToString()
进行服务器端脱水。把脱水后的代码,发送给客户端浏览器。这就完成了SSR
的第一步:脱水。
更多苏南大叔的react
经验文章,请参考:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。