new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

React Router · API · all subjects

error boundaries & edge cases

17 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Traditional state management approach is anti-pattern in React Router

The pattern of managing individual form fields in React state, adding change event listeners, implementing validation, and manually fetching to a server endpoint is an anti-pattern in React Router. This approach requires extensive state management, state synchronization, and duplication of validation logic between client and server.

Anti-pattern: managing network state in React state

Managing network-related state in React state is an anti-pattern in React Router. If your React state manages anything related to the network—such as data from loaders, pending form submissions, or navigational states—it's likely that you're managing state that React Router already manages through useNavigation, useFetcher, loaderData, and actionData.

Error boundaries not intended for form validation or error reporting

Error boundaries are not intended for rendering form validation errors or error reporting. See Form Validation and Error Reporting documentation instead.

Root error boundary required for all applications

All applications should at a minimum export a root error boundary to handle the three main error cases: thrown data with a status code and text, instances of errors with a stack trace, and randomly thrown values.

Framework mode error boundary example

import { Route } from "./+types/root"; export function ErrorBoundary({ error, }: Route.ErrorBoundaryProps) { if (isRouteErrorResponse(error)) { return ( <> <h1> {error.status} {error.statusText} </h1> <p>{error.data}</p> </> ); } else if (error instanceof Error) { return ( <div> <h1>Error</h1> <p>{error.message}</p> <p>The stack trace is:</p> <pre>{error.stack}</pre> </div> ); } else { return <h1>Unknown Error</h1>; } } This example shows how to handle three error types in Framework Mode: RouteErrorResponse with status code, Error instances with stack trace, and unknown errors.

Data mode error boundary uses useRouteError hook

In Data Mode, the ErrorBoundary component does not receive props. Instead, access the error using the useRouteError hook.

Data mode error boundary example

import { useRouteError } from "react-router"; let router = createBrowserRouter([ { path: "/", ErrorBoundary: RootErrorBoundary, Component: Root, }, ]); function Root() { /* ... */ } function RootErrorBoundary() { let error = useRouteError(); if (isRouteErrorResponse(error)) { return ( <> <h1> {error.status} {error.statusText} </h1> <p>{error.data}</p> </> ); } else if (error instanceof Error) { return ( <div> <h1>Error</h1> <p>{error.message}</p> <p>The stack trace is:</p> <pre>{error.stack}</pre> </div> ); } else { return <h1>Unknown Error</h1>; } } This example shows how to handle errors in Data Mode using useRouteError to access the error object.

Do not intentionally throw errors for control flow

It is not recommended to intentionally throw errors to force the error boundary to render as a means of control flow. Error Boundaries are primarily for catching unintentional errors in your code.

Errors caught in all route module APIs

Errors are caught not just in loaders but in all route module APIs: loaders, actions, components, headers, links, and meta.

throw data() for intentional errors like 404s

Exceptions to the rule about not throwing errors for control flow apply especially to 404s. You can intentionally throw data() with a proper status code to the closest error boundary when your loader can't find what it needs to render the page.

throw data() example for 404 errors

import { data } from "react-router"; export async function loader({ params }) { let record = await fakeDb.getRecord(params.id); if (!record) { throw data("Record Not Found", { status: 404 }); } return record; } This example shows how to throw data with a 404 status code when a record is not found, which renders the isRouteErrorResponse branch of the error boundary.

Closest error boundary is rendered for thrown errors

When an error is thrown, the closest error boundary in the component tree will be rendered, not a parent or root error boundary.

Nested error boundaries in framework mode resolution

When routes are nested in framework mode, errors are caught by the closest error boundary at that route level. If a route has no error boundary, the error is caught by the nearest parent route with an error boundary. For example: if app.tsx has an error boundary, invoices.tsx has none, and invoice-page.tsx has an error boundary, then errors from invoices.tsx render the app.tsx boundary, while errors from payments.tsx render the invoice-page.tsx boundary.

Nested error boundaries in data mode resolution

When routes are nested in data mode, errors thrown from a component are caught by the closest ErrorBoundary property defined in that route or its parent routes. If a route has no ErrorBoundary property, the error propagates up to the nearest parent route with an ErrorBoundary.

Error sanitization in framework mode production

In Framework Mode when building for production, any errors that happen on the server are automatically sanitized before being sent to the browser to prevent leaking sensitive server information like stack traces. A thrown Error will have a generic message and no stack trace in production in the browser. The original error is untouched on the server. Data sent with throw data(yourData) is not sanitized as that data is intended to be rendered.

Error Boundaries automatically catch errors and render closest boundary

Route modules automatically catch errors in your code and render the closest ErrorBoundary. Error boundaries handle three main cases: thrown data with a status code and text, instances of errors with a stack trace, and randomly thrown values.

Error and catch boundary distinction in Remix

Remix maintains a distinction between error and catch boundaries that is not present in React Router. This distinction must be preserved during the migration.

Give your agent this brain