03-状态管理与路由——08-懒加载与代码分割
懒加载与代码分割一、React.lazy 基础1.1 基本用法import { lazy, Suspense } from react; // 懒加载组件 const HomePage lazy(() import(./pages/HomePage)); const AboutPage lazy(() import(./pages/AboutPage)); const ContactPage lazy(() import(./pages/ContactPage)); function App() { return ( BrowserRouter Suspense fallback{div加载中.../div} Routes Route path/ element{HomePage /} / Route path/about element{AboutPage /} / Route path/contact element{ContactPage /} / /Routes /Suspense /BrowserRouter ); }1.2 命名导出组件的懒加载// 组件使用命名导出 // components/Button.js export const Button () button按钮/button; export const IconButton () button图标按钮/button; // 懒加载命名导出 const Button lazy(() import(./components/Button).then(module ({ default: module.Button })));二、路由级别代码分割2.1 为每个路由单独分割import { lazy, Suspense } from react; import { BrowserRouter, Routes, Route } from react-router-dom; // 路由级别懒加载 const Dashboard lazy(() import(./pages/Dashboard)); const Settings lazy(() import(./pages/Settings)); const Analytics lazy(() import(./pages/Analytics)); function App() { return ( BrowserRouter Suspense fallback{PageLoader /} Routes Route path/ element{Dashboard /} / Route path/settings element{Settings /} / Route path/analytics element{Analytics /} / /Routes /Suspense /BrowserRouter ); } function PageLoader() { return ( div classNamepage-loader Spinner / p加载页面中.../p /div ); }2.2 嵌套路由懒加载// 父组件 const DashboardLayout lazy(() import(./layouts/DashboardLayout)); // 子组件在 DashboardLayout 内部懒加载 function DashboardLayout() { return ( div Sidebar / main Suspense fallback{div加载中.../div} Outlet / /Suspense /main /div ); }三、组件级别代码分割3.1 条件加载function ModalContainer({ showModal }) { const [ModalComponent, setModalComponent] useState(null); useEffect(() { if (showModal !ModalComponent) { import(./Modal).then(module { setModalComponent(() module.default); }); } }, [showModal, ModalComponent]); if (!showModal) return null; if (!ModalComponent) return div加载弹窗.../div; return ModalComponent /; }3.2 使用 lazy 条件加载const HeavyChart lazy(() import(./HeavyChart)); function Dashboard({ showChart }) { return ( div {showChart ( Suspense fallback{div加载图表.../div} HeavyChart / /Suspense )} /div ); }四、错误处理import { lazy, Suspense } from react; const Component lazy(() import(./Component)); function App() { const [hasError, setHasError] useState(false); useEffect(() { const handleError () setHasError(true); window.addEventListener(error, handleError); return () window.removeEventListener(error, handleError); }, []); if (hasError) { return div加载失败请刷新页面/div; } return ( Suspense fallback{div加载中.../div} Component / /Suspense ); }五、配合 ErrorBoundaryclass ErrorBoundary extends React.Component { state { hasError: false }; static getDerivedStateFromError() { return { hasError: true }; } render() { if (this.state.hasError) { return div组件加载失败/div; } return this.props.children; } } // 使用 ErrorBoundary Suspense fallback{Loading /} LazyComponent / /Suspense /ErrorBoundary六、性能优化建议6.1 预加载// 鼠标悬停时预加载 const LazyComponent lazy(() import(./HeavyComponent)); function Component() { const preload () { import(./HeavyComponent); }; return ( div onMouseEnter{preload} Suspense fallback{div加载中.../div} LazyComponent / /Suspense /div ); }6.2 Webpack 魔法注释const Component lazy(() import( /* webpackChunkName: dashboard */ /* webpackPrefetch: true */ ./Dashboard ));七、小结要点说明React.lazy动态导入组件Suspense加载 fallback UI路由分割按路由拆分代码组件分割按需加载大型组件