这是React 面试中出现频率最高的问题之一也是企业项目部署时必须解决的问题。我会从懒加载原理 → 配置 → history刷新404 → 不同服务器解决方案 → 面试回答全面讲解。一、React 路由懒加载Lazy LoadReact 默认所有页面都会打包到一个 JS 中。例如src ├── pages │ ├── Home │ ├── Login │ ├── User │ └── Setting正常打包bundle.js ↓ 包含 Home Login User Setting第一次访问index.html ↓ bundle.js3M ↓ 全部下载即使用户只访问首页也要下载所有页面。所以需要按需加载Code SplitReact.lazy()React 官方提供import { lazy } from react; const Home lazy(() import(./pages/Home)); const Login lazy(() import(./pages/Login));实际上首页 ↓ Home.chunk.js 登录 ↓ Login.chunk.js 用户 ↓ User.chunk.js浏览器只下载当前页面。例如访问/只下载main.js Home.chunk.js访问/login再下载Login.chunk.js二、Suspense因为 JS 是异步加载。React 不知道什么时候加载完成。所以import { Suspense } from react; Suspense fallback{divLoading.../div} Routes ... /Routes /Suspense完整写法import { BrowserRouter, Routes, Route } from react-router-dom; import { lazy, Suspense } from react; const Home lazy(() import(./pages/Home)); const Login lazy(() import(./pages/Login)); export default function App() { return ( BrowserRouter Suspense fallback{div加载中.../div} Routes Route path/ element{Home /} / Route path/login element{Login /} / /Routes /Suspense /BrowserRouter ); }三、为什么懒加载能减少包大小正常main.js ↓ Home Login User Order Admin ...打包4MB懒加载main.js 200KB ↓ Home.chunk.js 100KB ↓ Login.chunk.js 80KB ↓ User.chunk.js 90KB首次200KB后续按需下载这就是Code Splitting代码分割Webpack/Vite 都支持。四、history 模式为什么刷新404React RouterBrowserRouter采用history APIURLlocalhost:3000/login第一次index.html ↓ React ↓ 识别 /login ↓ 渲染 Login 页面没有问题。但是刷新F5浏览器GET /login请求服务器服务器寻找 /login实际上没有 login.html于是404React 根本没机会运行。流程如下刷新 ↓ 浏览器 ↓ GET /login ↓ Nginx ↓ 找 login 文件 ↓ 不存在 ↓ 404五、为什么 HashRouter 不会Hashhttp://localhost:3000/#/login服务器收到GET /因为# 后面的内容 不会发送给服务器所以服务器始终返回index.htmlReact读取 #/login ↓ 跳转因此Hash 不会刷新404。六、history 模式解决方案核心思想无论访问什么路径都返回 index.html由 React 接管路由。方法一Nginx生产环境最常用配置location / { try_files $uri $uri/ /index.html; }意思访问 /login ↓ 有没有 login ↓ 没有 ↓ 返回 index.htmlReactBrowserRouter ↓ 匹配 /login ↓ Login 页面这是生产环境最推荐的方案。方法二ApacheIfModule mod_rewrite.c RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.html [QSA,L] /IfModule方法三Express(Node)app.use(express.static(build)); app.get(*, (req, res) { res.sendFile(path.join(__dirname, build/index.html)); });方法四Vite 开发环境开发npm run devVite 已经帮你处理了。刷新localhost:5173/login不会404。方法五Create React App开发服务器npm start也是自动处理。只有部署以后Nginx Apache Tomcat IIS需要配置。七、React Router v6 懒加载最佳实践可以将路由单独维护import { lazy } from react; const Home lazy(() import(../pages/Home)); const User lazy(() import(../pages/User)); export default [ { path: /, element: Home /, }, { path: /user, element: User /, }, ];AppSuspense fallback{Loading /} Routes {routes.map(item ( Route key{item.path} path{item.path} element{item.element} / ))} /Routes /Suspense这样更适合大型项目维护。八、history 与 hash 对比对比项BrowserRouterHistoryHashRouterURL/user#/user是否美观✅❌SEO✅ 更友好❌ 较差刷新需要服务器配置不需要服务端支持必须不需要推荐✅ 企业项目首选适合静态托管或无需服务端配置的场景九、面试高频回答如果面试官问React history 模式为什么刷新会 404如何解决可以回答BrowserRouter使用的是 HTML5 History API页面刷新时浏览器会向服务器请求当前路径例如/user。如果服务器上不存在对应的静态资源就会返回 404而 React 应用还没有机会接管路由。解决方法是在服务器配置回退规则Fallback例如 Nginx 使用try_files $uri $uri/ /index.html;Express 使用app.get(*, ...)返回index.html。这样所有前端路由都会先加载入口文件再由 React Router 根据 URL 渲染对应页面。十、企业项目常见优化大型 React 项目通常会结合以下方案进一步优化路由级懒加载使用React.lazy()Suspense按页面拆分代码减少首屏资源。预加载Prefetch/Preload对于用户大概率访问的页面可利用构建工具的预加载能力提前下载资源提高切换速度。加载状态优化为Suspense提供骨架屏Skeleton或 Loading 组件避免页面空白。错误边界Error Boundary处理懒加载模块加载失败如网络异常时的降级展示提高应用稳定性。合理拆分 Chunk避免过度拆分导致请求数量过多根据业务模块进行代码分割。这样既能提升首屏性能又能兼顾后续页面切换体验。