3

I am using React v17, and React Router v6+. When I load the page, the browser downloads all the js which is around 900kb, reducing the initial load time.

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.

How can I handle this ?

6
  • Are you doing const Buddy = lazy(() => import("../modules/Buddies/Buddy")); outside of a component ? Commented Jul 21, 2022 at 22:09
  • I just updated the question with the right component. The Buddy and other components are imported into App.js where the routes are defined Commented Jul 21, 2022 at 22:13
  • have you disabled caching in your browser? Can you clarify what is happening and what is expected result. I am getting a little lost on your explanation. Your first bit of the question make it sound it is loading correctly. If Profile and Buddy are pretty small it wont make a large difference because a majority of your app may be dependencies. thats why its 900kb to 999kb difference? Commented Jul 21, 2022 at 22:27
  • I've disabled caching. I will update the question. The problem is that when I load the app, the entire js is downloaded even when I have lazy loaded the routes. It should only load the JS it needs for a page, but it downloads the js for the entire app which is around 999kb and slows the page load. Commented Jul 21, 2022 at 22:32
  • @JulienKode There's no reason to promote your answer here in the comments, the OP will be notified that answers have been provided. Commented Jul 21, 2022 at 22:50

2 Answers 2

0

This is normal. You are wrapping the whole app with Suspense, which is directly resolved by your fallback while anything under it is suspended.

How to implement Suspense with react router ?

You should defined Suspense for each route you want to have lazy loading. So when the route is called, suspense will call the fallback while anything under it is suspended.

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

Sign up to request clarification or add additional context in comments.

4 Comments

This shouldn't make a difference the suspense is just a fall back catcher for when the element isn't in place not for code splitting. You would only do multiple suspense if you wanted a different "Loader" for each component.
yes it is, This is normal. he wrap all routes in Suspense, which is resolved by the fallback while anything under it is suspended.
unfortunately, this did not work for me. It still downloads the large bundle on first load
Can you create a codesandbox ?
0

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.

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.

Edit 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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.