Search code examples
reactjslazy-loadingreact-router-domreact-lazy-load

Implement lazy loading in nested routes


I'm trying to add implement lazy loading in react app which works well in top-level routes. But I also want the <Suspense></Suspense> and provide a fallback for nested routes. According to react-router-dom, there must be only Fragment or Route as the children of Routes. Is there any way to handle this?

Here is the code:

import { lazy, Fragment, Suspense } from "react";
import { BrowserRouter, Route, Routes, Navigate } from "react-router-dom";

import Header from "./components/Header";

const Home = lazy(() => import("./components/layout/Home"));
const Destination = lazy(() => import("./components/layout/Destination"));
const Planet = lazy(() => import("./components/Planet"));
const Crew = lazy(() => import("./components/layout/Crew"));
const Biography = lazy(() => import("./components/Biography"));
const Technology = lazy(() => import("./components/layout/Technology"));
const Procedure = lazy(() => import("./components/Procedure"));

function App() {
  return (
    <BrowserRouter>
      <Header />
      <Suspense fallback={<p className='fixed left-1/2 top-1/2 -translate-x-1/2 text-2xl'>Loading ...</p>}>
        <Routes>
          <Route path="/" element={<Navigate to="home" />} />
          <Route path="home" element={<Home />} />
          <Route path="destination" element={<Destination />}>
            <Route path=":id/:planet" element={<Planet />} />
          </Route>
          <Route path="crew" element={<Crew />}>
            <Route path=":id" element={<Biography />} />
          </Route>
          <Route path="technology" element={<Technology />}>
            <Route path=":id" element={<Procedure />} />
          </Route>
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

export default App;

Solution

  • You can wrap individual routed components in their own Suspense.

    Example:

    <BrowserRouter>
      <Header />
      <Suspense
        fallback={(
          <p className='fixed left-1/2 top-1/2 -translate-x-1/2 text-2xl'>
            Loading ...
          </p>
        )}
      >
        <Routes>
          ...
          <Route path="destination" element={<Destination />}>
            <Route
              path=":id/:planet"
              element={(
                <Suspense fallback={<>Loading Planet ...</>}>
                  <Planet />
                </Suspense>
              )}
            />
          </Route>
          ...
        </Routes>
      </Suspense>
    </BrowserRouter>