简体   繁体   English

如何使用 react-router 实现延迟加载和代码拆分?

[英]How to implement lazy loading and code splitting with react-router?

I am using React v17, and React Router v6+.我正在使用 React v17 和 React Router v6+。 When I load the page, the browser downloads all the js which is around 900kb, reducing the initial load time.当我加载页面时,浏览器下载了大约 900kb 的所有 js,减少了初始加载时间。

My routes are defined like so我的路线是这样定义的

const PrivateRoute = lazy(() => import("../utils/AuthenticatedRoutes"));
const Profile = lazy(() => import("../modules/Settings/User/Profile"));
const Buddies = lazy(() => import("../modules/Buddies/Buddies"));
const Buddy = lazy(() => import("../modules/Buddies/Buddy"));

const App = () => {
      return (
        <Suspense fallback={<Loader />}>
            <Routes>
                <Route path="/" element={<Landing />} />
                <Route path="/profile" element={<PrivateRoute render={<Profile />} />} />
                <Route path="/buddies" element={<PrivateRoute render={<Buddy />} />} />
            </Routes>
        </Suspense>
      )
}
   

This is the Private Route component这是私有路由组件


const PrivateRoute = ({ render }: { render: any }) => {
    const location = useLocation();
    const { loggedIn } = useSelector((state: RootState) => state.userReducer);

    const pathname = location.pathname;

    if (!loggedIn) {
        return <Navigate to={`/login?redirectTo=${pathname}&search=${location.search}`} />;
    }

    return render;
};

Problem: When I load any page on the app, even the one with no element in it, the entire JS of 999kb is downloaded and I don't think lazy loading should work that way.问题:当我在应用程序上加载任何页面时,即使是没有元素的页面,也会下载 999kb 的整个 JS,我认为延迟加载不应该以这种方式工作。

How can I handle this ?我该如何处理?

This is normal.这个是正常的。 You are wrapping the whole app with Suspense, which is directly resolved by your fallback while anything under it is suspended.您正在使用 Suspense 包装整个应用程序,这将由您的后备直接解决,而其下的任何内容都被暂停。

How to implement Suspense with react router ?如何使用react router实现Suspense

You should defined Suspense for each route you want to have lazy loading.您应该为每个想要延迟加载的路由定义Suspense So when the route is called, suspense will call the fallback while anything under it is suspended.所以当路由被调用时,suspense 将调用回退,而它下面的任何东西都被挂起。

const PrivateRoute = lazy(() => import("../utils/AuthenticatedRoutes"));
const Profile = lazy(() => import("../modules/Settings/User/Profile"));
const Buddies = lazy(() => import("../modules/Buddies/Buddies"));
const Buddy = lazy(() => import("../modules/Buddies/Buddy"));

const App = () => {
      return (

            <Routes>
                <Route path="/" element={<Landing />} />
                <Route path="/profile" element={<PrivateRoute render={<React.Suspense fallback={<Loader />}><Profile /></React.Suspense>} />} />
                <Route path="/buddies" element={<PrivateRoute render={<React.Suspense fallback={<Loader />}><Buddy /></React.Suspense>} />} />
            </Routes>
      )
}

This is the same as the official documentation这个和官方文档一样

I don't see any overt issues with the way you've implemented your code.我没有看到您实现代码的方式有任何明显的问题。 The code splitting appears to be working.代码拆分似乎正在工作。

Suggestion建议

I suggest refactoring the PrivateRoute component to be a layout route component instead of a wrapper component.我建议将PrivateRoute组件重构为布局路由组件,而不是包装器组件。

Example:例子:

import { Navigate, Outlet, useLocation } from 'react-router-dom';

const PrivateRoute = () => {
  const location = useLocation();
  const { loggedIn } = useSelector((state: RootState) => state.userReducer);

  const pathname = location.pathname;

  if (!loggedIn) {
    return <Navigate to={`/login?redirectTo=${pathname}&search=${location.search}`} />;
  }

  return <Outlet />;
};

... ...

const PrivateRoute = lazy(() => import("../utils/AuthenticatedRoutes"));
const Profile = lazy(() => import("../modules/Settings/User/Profile"));
const Buddies = lazy(() => import("../modules/Buddies/Buddies"));
const Buddy = lazy(() => import("../modules/Buddies/Buddy"));

const App = () => {
  return (
    <Suspense fallback={<Loader />}>
      <Routes>
        <Route path="/" element={<Landing />} />
        <Route element={<PrivateRoute />}>
          <Route path="/profile" element={<Profile />} />
          <Route path="/buddies" element={<Buddy />} />
        </Route>
      </Routes>
    </Suspense>
  )
}

With this implementation I do see the Loader component "blip" on the screen momentarily for the first time each dynamically imported component is routed to.通过这个实现,我确实第一次在屏幕上看到了Loader组件“blip”,每个动态导入的组件都被路由到。

编辑 how-to-implement-lazy-loading-and-code-splitting-with-react-router

I think it might be as Colin called out in a comment, that the dynamically imported components just aren't a significant portion of your overall app bundle size.我认为这可能就像 Colin 在评论中所说的那样,动态导入的组件并不是整个应用程序包大小的重要部分。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM