实现思路
- 路由处理:在服务端根据请求的路径和用户角色,确定需要加载的数据。
- 异步数据加载:使用
async/await
或 Promise.all
等方式异步加载数据。
- 数据注入:将加载好的数据注入到React组件树的上下文或props中。
- 避免水合问题:确保服务端和客户端的数据一致,通常做法是在服务端渲染时将数据序列化并嵌入到HTML中,客户端渲染时直接使用这些数据。
相关代码框架
- 路由处理:使用
react-router
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
function App() {
return (
<Router>
<Routes>
<Route path="/teacher" element={<TeacherPage />} />
<Route path="/student" element={<StudentPage />} />
</Routes>
</Router>
);
}
- 异步数据加载:以教师页面加载学生成绩数据为例
async function getStudentScores() {
// 模拟异步请求
return new Promise((resolve) => {
setTimeout(() => {
resolve([{ student: 'Alice', score: 90 }, { student: 'Bob', score: 85 }]);
}, 1000);
});
}
function TeacherPage() {
const [studentScores, setStudentScores] = useState([]);
useEffect(() => {
async function fetchData() {
const scores = await getStudentScores();
setStudentScores(scores);
}
fetchData();
}, []);
return (
<div>
<h1>Teacher Page</h1>
{studentScores.map((score) => (
<p>{score.student}: {score.score}</p>
))}
</div>
);
}
- 数据注入:在服务端渲染时使用
context
或 props
传递数据
// 服务端渲染
import React from'react';
import ReactDOMServer from'react-dom/server';
import { StaticRouter } from'react-router-dom/server';
import App from './App';
async function renderApp(req) {
const studentScores = await getStudentScores();
const context = {};
const html = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App studentScores={studentScores} />
</StaticRouter>
);
return html;
}
- 避免水合问题:将服务端数据序列化嵌入HTML
// 服务端渲染
import React from'react';
import ReactDOMServer from'react-dom/server';
import { StaticRouter } from'react-router-dom/server';
import App from './App';
async function renderApp(req) {
const studentScores = await getStudentScores();
const context = {};
const html = ReactDOMServer.renderToString(
<StaticRouter location={req.url} context={context}>
<App studentScores={studentScores} />
</StaticRouter>
);
const serializedData = JSON.stringify(studentScores);
return `
<!DOCTYPE html>
<html>
<head>
<title>SSR App</title>
</head>
<body>
<div id="root">${html}</div>
<script>
window.__INITIAL_DATA__ = ${serializedData};
</script>
<script src="/client.js"></script>
</body>
</html>
`;
}
// 客户端渲染
import React from'react';
import ReactDOM from'react-dom/client';
import { BrowserRouter } from'react-router-dom';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
const initialData = window.__INITIAL_DATA__;
root.render(
<BrowserRouter>
<App studentScores={initialData} />
</BrowserRouter>
);