如何对通过exporter.js导出的默认组件实现React懒加载?
问题
我维护了一个单独的文件exporter.js,用来统一导入并导出组件,简化其他文件的导入语句,代码如下:
export { default as Posts } from './Posts/Posts'; export { default as Form } from './Form/Form'; export { default as Home } from './Home'; export { default as Footer} from "./Footer/Footer"; export { default as Header} from "./Header/Header"; export { default as AllPosts} from "./AllPosts/AllPosts"; export { default as LoginAndRegister} from "./LoginAndRegister/LoginAndRegister";
随后在main.js中按如下方式导入组件并配置路由:
import './index.css' import React from 'react' import store from './app/store.js' import { Provider } from 'react-redux' import ReactDOM from 'react-dom/client' import Layout from './components/Layout.jsx' import { Toaster } from './components/ui/toaster.jsx' import { fetchMemoryPosts } from './features/postsSlice.js'; import { Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from 'react-router-dom'; //********************* importing components***************************** import { Home, LoginAndRegister, AllPosts } from './components/exporter.js' //*********************************************************************** const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<Layout />}> <Route path='' element={<AllPosts />}/> <Route path='/register-login' element={<LoginAndRegister />} /> <Route path='/my-memories' element={<Home />} /> </Route> ) ) store.dispatch(fetchMemoryPosts()); ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <Provider store={store}> <RouterProvider router={router} /> <Toaster /> </Provider> </React.StrictMode>, )
请问如何为这些从./components/exporter.js导入的Home、LoginAndRegister、AllPosts组件应用React懒加载?
解决方案
要给这些组件应用懒加载,需要用到React的lazy和Suspense特性,下面提供两种可行的实现方式:
方式一:直接在路由中配置懒加载(无需修改exporter.js)
不需要改动exporter.js,直接在main.js中用React.lazy懒加载目标组件,同时用Suspense包裹路由组件,提供加载时的占位内容:
修改main.js的相关代码:
import './index.css' import React, { lazy, Suspense } from 'react' // 引入lazy和Suspense import store from './app/store.js' import { Provider } from 'react-redux' import ReactDOM from 'react-dom/client' import Layout from './components/Layout.jsx' import { Toaster } from './components/ui/toaster.jsx' import { fetchMemoryPosts } from './features/postsSlice.js'; import { Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from 'react-router-dom'; // 用React.lazy懒加载组件,替代原来从exporter导入的方式 const Home = lazy(() => import('./components/Home')); const LoginAndRegister = lazy(() => import('./components/LoginAndRegister/LoginAndRegister')); const AllPosts = lazy(() => import('./components/AllPosts/AllPosts')); // 定义加载占位组件 const Loading = () => <div>加载中...</div>; const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<Layout />}> {/* 用Suspense包裹每个懒加载组件的路由 */} <Route path='' element={ <Suspense fallback={<Loading />}> <AllPosts /> </Suspense> }/> <Route path='/register-login' element={ <Suspense fallback={<Loading />}> <LoginAndRegister /> </Suspense> } /> <Route path='/my-memories' element={ <Suspense fallback={<Loading />}> <Home /> </Suspense> } /> </Route> ) ) store.dispatch(fetchMemoryPosts()); ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <Provider store={store}> <RouterProvider router={router} /> <Toaster /> </Provider> </React.StrictMode>, )
方式二:修改exporter.js导出懒加载组件
如果你想继续通过exporter.js统一管理懒加载组件,可以修改该文件,把需要懒加载的组件用React.lazy包装后导出:
第一步:修改exporter.js
// 非懒加载组件保持原有导出方式 export { default as Posts } from './Posts/Posts'; export { default as Form } from './Form/Form'; export { default as Footer} from "./Footer/Footer"; export { default as Header} from "./Header/Header"; // 需要懒加载的组件用React.lazy包装后导出 export const Home = React.lazy(() => import('./Home')); export const AllPosts = React.lazy(() => import('./AllPosts/AllPosts')); export const LoginAndRegister = React.lazy(() => import('./LoginAndRegister/LoginAndRegister'));
第二步:修改main.js引入并使用Suspense
import './index.css' import React, { Suspense } from 'react' // 引入Suspense import store from './app/store.js' import { Provider } from 'react-redux' import ReactDOM from 'react-dom/client' import Layout from './components/Layout.jsx' import { Toaster } from './components/ui/toaster.jsx' import { fetchMemoryPosts } from './features/postsSlice.js'; import { Route, RouterProvider, createBrowserRouter, createRoutesFromElements } from 'react-router-dom'; // 从exporter导入懒加载组件 import { Home, LoginAndRegister, AllPosts } from './components/exporter.js' // 定义加载占位组件 const Loading = () => <div>加载中...</div>; const router = createBrowserRouter( createRoutesFromElements( <Route path="/" element={<Layout />}> <Route path='' element={ <Suspense fallback={<Loading />}> <AllPosts /> </Suspense> }/> <Route path='/register-login' element={ <Suspense fallback={<Loading />}> <LoginAndRegister /> </Suspense> } /> <Route path='/my-memories' element={ <Suspense fallback={<Loading />}> <Home /> </Suspense> } /> </Route> ) ) store.dispatch(fetchMemoryPosts()); ReactDOM.createRoot(document.getElementById('root')).render( <React.StrictMode> <Provider store={store}> <RouterProvider router={router} /> <Toaster /> </Provider> </React.StrictMode>, )
注意事项
React.lazy只能用于默认导出的组件,如果组件是命名导出,需要调整导入方式:() => import('./Component').then(mod => ({ default: mod.NamedComponent }))Suspense的fallback属性必须是React元素,可设置加载动画、文字提示等占位内容- 可以将
Suspense放在更高层级的路由上(比如包裹整个Layout),让所有子路由的懒加载组件共用同一个加载占位,减少重复代码
内容的提问来源于stack exchange,提问作者Abinash
相关产品推荐
相关产品推荐

