Giter Site home page Giter Site logo

`useRouteLoaderData("root")` returns `undefined` in root's `ErrorBoundary`/`Layout` when non-existent page is loaded right away. about remix HOT 10 CLOSED

ansavchenco avatar ansavchenco commented on May 21, 2024
`useRouteLoaderData("root")` returns `undefined` in root's `ErrorBoundary`/`Layout` when non-existent page is loaded right away.

from remix.

Comments (10)

kiliman avatar kiliman commented on May 21, 2024 2

If you need 404 to execute the root loader, add a splat route and throw a 404 response. This will force Remix to go through the usual route process.

// routes/$.tsx
export function loader() {
  throw new Response('Not Found', { status: 404 });
}

export default function Component() {
  return null;
}

https://stackblitz.com/edit/remix-run-remix-z7wwii?file=app%2Froutes%2F%24.tsx

from remix.

ansavchenco avatar ansavchenco commented on May 21, 2024 1

Yep, this solved the problem for me! Thank you!
Feel free to close the issue if non-existing routes not triggering the root loader is considered working as expected.

from remix.

brophdawg11 avatar brophdawg11 commented on May 21, 2024 1

I'm going to close this out as expected since without a splat route no route paths match so there's no root match to render. The splat route solution recommended above is the correct solution.

As for the FOUC, I believe that's expected but if you wouldn't mind opening a new issue we could use that to discuss and confirm.

From a quick look, I think it's a vite dev only issue since vite does a request for a 304 not modified response for assets in dev mode - if you do npm run build/npm run start and leverage caching headers the browser can re-use the stylesheet across the switch from UI to Error Boundary so there's no flash.

The reason the layout get's unmounted/remounted is that under the hood the React Router tree looks essentially like this:

let routes = [{
  id: 'root',
  path: '/',
  element: <Layout><RootComponent /></Layout>,
  errorElement: <Layout><RootErrorBoundary /></Layout>,
  children: ...
}];

So it's a new React.createElement call for Layout when it's being used as the component versus the error boundary. There's not really any place "above" there to use the same instance but maybe it's possible we could investigate that as part of the new issue.

The workaround for now is to use a pathless route for the error boundary which would allow the root Layout to remain mounted when going from UI to 404 routes:

root.tsx              // Layout
routes/_pathless.tsx  // ErrorBoundary
routes/_pathless._index.tsx
routes/_pathless.$.tsx

from remix.

woble avatar woble commented on May 21, 2024

This might give you the answer

#8951 (comment)

from remix.

ansavchenco avatar ansavchenco commented on May 21, 2024

Thanks! Checked it out and it suggests to use the useRouteLoaderData which i'm already using. It returns undefined for a URL with no matching route even though the loader can still be run and return data without any errors. I have updated the Expected/Actual Behavior sections to make it more clear.

from remix.

kiliman avatar kiliman commented on May 21, 2024

Take a look at https://github.com/kiliman/remix-global-data

This explains the reasons and gives a possible solution.

from remix.

ansavchenco avatar ansavchenco commented on May 21, 2024

I couldn't find any explanation for the problem i described in the linked article. It explains why useLoaderData should not be used within ErrorBoundary and suggests to use useRouteLoaderData instead and check its result for undefined which i'm already doing. The issue is that when hitting a URL for which there is no route registered the root loader doesn't seem to run at all and therefore useRouteLoaderData("root") returns undefined.

Also, not sure the global data approach suggested by the article would work for the CSP nonce since it has to be generated on every request and not just once when the app starts.

from remix.

kiliman avatar kiliman commented on May 21, 2024

Remix doesn't bother calling the root loader for a route that doesn't exist. That's why even useRouteLoaderData('root') returns undefined.

What data are you trying to show in your ErrorBoundary?

from remix.

ansavchenco avatar ansavchenco commented on May 21, 2024

Well, /non-existent is still a child of / so just logically i would expect the root loader to run for it too 🤓

  • The use-case for it is a layout that's shared between root route and root error boundary (what Layout export is for). Let's say there is a navbar with current user information. This information is loaded from the root route and in my error boundary i would still want to show that navbar so i need the root loader data.
  • Another thing is the CSP nonce which has to be provided to ScrollRestoration and Scripts components. The nonce is also loaded in the root loader. If the data is not there then the scripts execution will be blocked by CSP and Remix documentation states that at least Scripts has to be present in root error boundary.

You'll want to make sure to still render the Links, Meta, and Scripts components because the whole document will mount and unmount when the root error boundary is rendered.

Please, check the stackblitz that i provided. It highlights both of the above use-cases.

from remix.

ansavchenco avatar ansavchenco commented on May 21, 2024

Noticed one thing though. The Layout doesn't seem to help with FOUC when going back and forth between error boundary and regular content. Here is the updated stackblitz with styles to make it noticeable:
https://stackblitz.com/edit/remix-run-remix-cqfze8?file=app%2Froutes%2F_index.tsx

This probably deserves a separate issue. There is one issue closed that looks similar to what i'm experiencing - #1136 (comment)

Edited: the FOUC doesn't happen 100% of the time. Seems like it has something to do with how fast you actually click back/forward after landing on a page.

from remix.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.