实现简易 React SSR 框架
框架依赖
- express
- react
- react-dom
创建一个 node server
使用 express 创建一个 node server
js
import express from 'express'
import handlerSsr from './ssr'
const app = express()
const port = process.env.PORT || 3000
app.use(express.static('public'))
app.get('*' , (req, res) => {
// 处理 SSR 逻辑
return handlerSsr(req, res)
})
app.listen(port, () => {
console.log(`Server started on http://localhost:${port}`)
});
创建一个根组件
js
// client/App.js
import React from 'react';
function App(props) {
return <div>Hello World!</div>;
}
export default App;
处理 SSR 逻辑
主要分为以下几个步骤:
- 解析请求:确定当前请求的URL和任何查询参数。
- 获取数据:对于动态内容,您可能需要从数据库或外部API获取数据。
- 渲染React组件树:使用收集到的数据渲染您的React组件树。
- 序列化HTML:将渲染后的React组件转换为静态HTML字符串。
- 发送响应:将最终的HTML字符串发送回浏览器。
js
import App from './App'
export const handlerSsr = (req, res) => {
// 处理请求
const url = req.path
const handleRequest = async () => {
const data = await getDataPage(url);
if (!data) {
res.statusCode = 404;
res.end('Not Found');
return;
}
const html = renderPage(data);
res.write(html);
res.end();
};
// 获取数据(在真实场景中,这部分很可能是异步的)
const getDataPage = async (url) => {
// 模拟从数据库或API获取数据的行为
switch (url) {
case '/':
return { title: 'Home', message: 'Welcome home!' };
case '/about':
return { title: 'About Us' };
default:
return null;
}
};
// 渲染React组件树
const renderPage = (data) => {
const renderedContent = ReactDOMServer.renderToString(
<App {...data} /> // 将数据作为props传递给App组件
);
return `
<!doctype html>
<html>
<head>
<meta charset=utf-8/>
<title>${data.title}</title>
</head>
<body>
<div id="root">${renderedContent}</div>
<script type="text/javascript" src="index_bundle.js"></script>
</body>
</html>
`;
};
handleRequest()
.catch((err) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
}