MST

星途 面试题库

面试题:React服务端渲染条件逻辑中处理异步数据加载

在React SSR应用中,页面需要根据用户角色来异步加载不同的数据。例如,教师角色加载学生成绩数据,学生角色加载自己的课程表数据。请阐述如何在服务端渲染的条件逻辑中,优雅地处理这种异步数据加载,保证数据在渲染前正确获取,同时避免水合(hydration)问题,给出具体实现思路及相关代码框架。
25.8万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 路由处理:在服务端根据请求的路径和用户角色,确定需要加载的数据。
  2. 异步数据加载:使用 async/awaitPromise.all 等方式异步加载数据。
  3. 数据注入:将加载好的数据注入到React组件树的上下文或props中。
  4. 避免水合问题:确保服务端和客户端的数据一致,通常做法是在服务端渲染时将数据序列化并嵌入到HTML中,客户端渲染时直接使用这些数据。

相关代码框架

  1. 路由处理:使用 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>
  );
}
  1. 异步数据加载:以教师页面加载学生成绩数据为例
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>
  );
}
  1. 数据注入:在服务端渲染时使用 contextprops 传递数据
// 服务端渲染
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;
}
  1. 避免水合问题:将服务端数据序列化嵌入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>
);