skip to Main Content

I am trying to lazy load a component in React. It works if I declare the component at the top of the module. However it does not render anything if I declare it in a inline way.

Case 1 : Works as expected

import React, { lazy, Suspense } from "react";
import { Routes, Link, Route, Outlet } from "react-router-dom";
import CaseStudies from "./pages/CaseStudies";

const ExampleAssembly = lazy(() => import("./pages/ExampleAssembly"));

export default function App() {
  return (
    <>
      <Suspense fallback={<p>Loading...</p>}>
        <Routes>
          <Route path="/casestudies" element={<CaseStudies />} >
            <Route path="assembly" element={<ExampleAssembly />} />
          </Route>
        </Routes>
      </Suspense>
    </>
  );
}

Case 2: Doesn’t work

import React, { lazy, Suspense } from "react";
import { Routes, Link, Route, Outlet } from "react-router-dom";
import CaseStudies from "./pages/CaseStudies";

export default function App() {
  return (
    <>
      <Suspense fallback={<p>Loading...</p>}>
        <Routes>
          <Route path="/casestudies" element={<CaseStudies />} >
            <Route path="assembly" element={ lazy(() => {
              return import("./pages/ExampleAssembly");
            })  } />
          </Route>
        </Routes>
      </Suspense>
    </>
  );
}

Is there a correct way to write inline lazy loaded components? Or should I always have lazy loaded component definitions at the top as in Case1?

2

Answers


  1. Always do it like how you have it in case 1. You’re trying to force a pattern that doesn’t, and shouldn’t, exist in the other example.

    Login or Signup to reply.
  2. Short answer: you should always load your component definitions at the top as in Case 1.

    lazy is not designed to be used in the inline fashion that you describe. As the React docs say:

    lazy returns a React component you can render in your tree

    So, it’s failing in Case 2 because you’re using lazy‘s return value as a function, rather than as a component, which is why React logs an error Warning: Functions are not valid as a React child.

    You could use the return value with createElement, in which case it does actually render:

                // WARNING: BAD IDEA, NOT FOR PRODUCTION USE
                <Route path="assembly" element={ 
                  React.createElement(
                    lazy(() => {
                      return import("./pages/ExampleAssembly");
                    })
                  )
                } />
    

    This is, however, creating a new lazy component every time the Route is rendered. It’s essentially the same as declaring a new component in a function scope, which is a definite anti-pattern, except it also involves a Promise that does network loading on every render. Just … don’t do it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search