react-router: [Bug]: Nested routing ( inside )

What version of React Router are you using?

6.10.0

Steps to Reproduce

Example: I wrote a full example on Codesandbox for reproducing, please have a look: https://codesandbox.io/s/react-router-v6-action-error-edbuhu?file=/src/business/business.js

image

Explanation:

I use <RouterProvider /> in the root, but I have another router inside (for my header) where I show components (search, filtering, selectors) depending on routing. Other words inside the root “Layout” component exist a “Header” component where exist nested routes <Routes><Route.../></Routes>

Steps for reproduce: Press the button “Submit. Press and get an error.” below on the page and get an error.

To fix the problem, comment in the opened file: (business/business.js file) // export const APP_ENABLE_NESTED_ROUTES = true;

Conclusion: Nested routes broke errorElement handling. Why?

Thanks for your attention, Andrii Badekha

Expected Behavior

After pressing the button: “Submit. Press and get an error.”,

Expect message on UI: Exception properly handled in <PageError />

I expect that my “errorElement” will catch an error and process them, but instead, the react-router shows a general error, not my error handler component.

Actual Behavior

After pressing the button: “Submit. Press and get an error.”,

Get the error: Error: Could not find a matching route for the current errors: [object Object]

As a result, my errorElement was missed, I read additionally documentation and seems like it is unexpected behaviour, docs don’t cover this case.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Reactions: 1
  • Comments: 18 (12 by maintainers)

Most upvoted comments

because if it’s not recommended officially we can’t use it for production

I think this needs some clarification, as this is not an accurate statement. I’ve tried to clarify some of the confusion here and here.

To try to summarize:

  • If you are starting a brand new <RouterProvider> application, then yes, we generally wouldn’t advise the usage of nested <Routes> since you lose out on the new data APIs.
  • If you are migrating a BrowserRouter application to use <RouterProvider> then you can and should keep using your existing nested <Routes> during the migration which allows you to migrate routes one by one up to the root createBrowserRouter. The end goal would be eventually getting rid of all of the nested <Routes>. But it is absolutely expected that <RouterProvider> + <Routes> can ship to production.

We are working on better docs for this BrowserRouter -> RouterProvider migration to try to clear up some of the common misconceptions.

This is as expected. According to the docs, “If you’re using a data router like createBrowserRouter it is uncommon to use this component as it does not participate in data loading.”. This includes error handling.

The error you’re getting is because <Routes> does not read the errorElement (or loader) prop from your <Route>s and is essentially passing null to the browser router. This is partially from some internal implementation details, but combining the two APIs and structures together is not recommended anyways.

@jasikpark Nice catch, I believe “errorElement” here is then an exception as a rule https://reactrouter.com/en/main/route/route

Let’s have a look at an example from docs: image

And what are the types for <Route />: image

What I am thinking is that “<RouterProvider />” should be the only one on the page and <Route /> should work with “createRoutesFromElements” and mainly created for migration from v5 to v6

But if we trying create our own nested routes like this one: image

We got typescript IntelliSense for allowed properties, but it’s the wrong properties, because our <Route /> is not inside the function “createRoutesFromElements” and we got the wrong IntelliSense and a lot of them shouldn’t work

I think that “errorElement” is somehow connected with internal realization and now it works and doesn’t matter where is <Route /> declared

As mentioned @timdorr “The error you’re getting is because <Routes> does not read the errorElement (or loader) prop from your <Route>s and is essentially passing null to the browser router. This is partially from some internal implementation details, but combining the two APIs and structures together is not recommended anyways.”

I believe we can get a lot of different issues here because “combining the two APIs and structures together is not recommended anyways” and this a reason why I conclude “If we need something similar to “nested routes” we need to create our own “custom routes component” and according to current location load the proper “component”.” because if it’s not recommended officially we can’t use it for production

🤖 Hello there,

We just published version 6.11.0-pre.0 which involves this issue. If you’d like to take it for a test run please try it out and let us know what you think!

Thanks!

This is fixed by #10374 and will be available once React Router 6.11.0 is released.

I pulled this example down and I think there’s an actual bug in here so I’m going to re-open this.

There’s some confusion around the usage of <Routes> inside a RouterProvider and I tried to elaborate a bit in this comment, but generally speaking:

  • You can Render descendant <Routes> inside a <RouterProvider>
  • <Route>'s below a <Routes> component cannot participate in data loading, which includes loader/action/errorElement/handle/shouldRevalidate etc.
    • However, the presence of descendant <Routes> should not break error handling at the RouterProvider layer, which seems to be what is happening in this bug.

I think this is what I am also experiencing, though I’m not positive.

I read this guide to errorElement: https://reactrouter.com/en/main/route/error-element#bubbling, which says:

When a route does not have an errorElement, errors will bubble up through parent routes. This lets you get as granular or general as you like.

Put an errorElement at the top of your route tree and handle nearly every error in your app in one place.

I can’t find any caveats on that page about how the use of a Routes component will break this behavior. Is that something you’d be willing to include in the docs? I’m still a bit confused how the two are related.

For RouterProvider, yes.

Let’s please stop using this closed issue as a Q&A forum and open new Q&A discussions for questions moving forward.

Is https://reactrouter.com/en/main/route/lazy the main way to allow splitting routes into separate files?

The “Data APIs” do not (and can not) work in BrowserRouter/<Routes> because they rely on the decoupling of route-definition/data-fetching and rendering. Here’s a list of the APIs that only work in RouterProvider: https://reactrouter.com/en/main/routers/picking-a-router#data-apis.

If you want error boundaries in Routes, you can just use them directly in your routes to capture rendering errors in children routes, there’s no need to try to abstract them through the router:

<BrowserRouter>
  <Routes>
    <Route element={<MyErrorBoundary><Outlet/></MyErrorBoundary>}>
      ...
    </Route>
  </Routes>
</BrowserRouter>

https://codesandbox.io/s/wizardly-feynman-mxvpnt?file=/src/index.js

🤖 Hello there,

We just published version 6.11.0 which involves this issue. If you’d like to take it for a test run please try it out and let us know what you think!

Thanks!

Hi everyone, the issue has been solved, thank you Modified example with “6.11.0-pre.0”: codesandbox.io/s/react-router-v6-action-error-forked-solved-7th46y?file=/src/business/business.js

wait… is that allowing an errorElement to be used on a Routes Route? I thought that wasn’t permitted?

Hi everyone, the issue has been solved, thank you Modified example with “6.11.0-pre.1”: https://codesandbox.io/s/react-router-v6-action-error-forked-solved-7th46y?file=/src/business/business.js