react-router: [v6] useRoutes does not work with loadable/component

Version

6.0.0-alpha.5

Test Case

https://codesandbox.io/s/react-router-loadable-component-t97j0?file=/src/App.jsx

Steps to reproduce

I created a route config array and added the name of the page component as a string:

const routes = [
  {
    path: "/",
    componentName: "Home"
  },
  {
    path: "/about",
    componentName: "About"
    children: [
      {
        path: "me",
        componentName: "AboutMe"
      }
    ]
  },
  {
    path: "/users",
    componentName: "Users"
    children: [
      {
        path: ":user",
        componentName: "User"
      }
    ]
  }
]

I created a component <AsyncPage component="componentName" /> which returns a loadable/component:

const AsyncPage = loadable(props => import(`./pages/${props.component}`));

I created a function to recursively map the <AsyncPage> to the element property.

const mapRoutesForUse = routes => {
  return routes.map(({ path, componentName, children }) => ({
    path,
    element: <AsyncPage component={componentName} />,
    children: children && mapRoutesForUse(children)
  }));
};

I created a <ProjectRoutes> component with useRoutes:

const ProjectRoutes = () => useRoutes(mapRoutesForUse(routes));

I added the <ProjectRoutes /> component to my App:

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to="/">Home</Link>
        </li>
        <li>
          <Link to="/about">About</Link>
          <ul>
            <li>
              <Link to="/about/me">Me</Link>
            </li>
          </ul>
        </li>
        <li>
          <Link to="/users">Users</Link>
        </li>
      </ul>
      <ProjectRoutes />
    </div>
  );
};

I added an <Outlet> component to the <About> and <Users> page components:

const About = () => (
  <>
    <h1>About Page</h1>
    <Outlet />
  </>
);

Expected Behavior

I would expect this setup to work and the router to render the requested pages.

Actual Behavior

  • When you are on the “Home” page of the testcase and you click on a link in the navigation, the URL changes but does not get rendered.
  • When you are on the “About” page and click on the “Home” or “Users” link nothing happens. But clicking on the “Me” link works!
  • When you are on the “Me” page and click on the “Home” or “Users” link it will take you to “About”.
  • When you are on the “Users” page its same as on the “About” page. Clicking the links to the “User” pages works but clicking on “Home” or “About” takes you again to “Users”.

Workaround

I created a function to recursively map the route config to <Route> components:

const mapRoutes = routes => {
  return routes.map(({ path, componentName, children }, key) => (
    <Route
      path={path}
      key={key}
      element={<AsyncPage component={componentName} />}
      children={children && mapRoutes(children)}
    />
  ));
};

And use it in the App like this:

      ...
      </ul>
      <Routes>{mapRoutes(routes)}</Routes>
    </div>
  );
};

This works great and every link navigates to the correct page. But shouldn’t this be the same as what useRoutes returns?

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 5
  • Comments: 18

Most upvoted comments

Okay i understand. Thank you very much for your help, it’s greatly appreciated! I can finally close this issue.


For everyone having problems to get typescript + react-router v6 + loadable components to work, look at this sandbox from @danilobrinu : https://codesandbox.io/s/falling-smoke-ye0jz?file=/src/App.tsx

@shwao I have no idea how much time you just saved me. I started with useRoutes, and the component mounting behavior was working well until I changed something. Unfortunately, I was not able to pin down exactly what change caused it to no longer work correctly, much to my frustration. I think it may have something to do with how the useRoutes is nested, because I was implementing error handling when it stopped working. I’m suspicious that there may be something to do with classed, functional, or a mixture of classed and functional components in the useRoutes lineage that causes this behavior, but investigating this is not something I can commit time to ATM.

Thank you very much for your workaround (I can confirm that it resolved my issue as well), and yes - I think this behavior may be worth understanding so that it can have test cases or documentation written against it.