Skip to content

Commit

Permalink
Final docs upates
Browse files Browse the repository at this point in the history
  • Loading branch information
brophdawg11 committed Mar 8, 2023
1 parent 6d79d3d commit 2560422
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 12 deletions.
42 changes: 42 additions & 0 deletions .changeset/component-and-error-boundary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
"react-router": minor
"react-router-dom": minor
---

React Router now supports an alternative way to define your route `element` and `errorElement` fields as React Components instead of React Elements. You can instead pass a React Component to the new `Component` and `ErrorBoundary` fields if you choose. There is no functional difference between the two, so use whichever approach you prefer 😀. You shouldn't be defining both, but if you do `Component`/`ErrorBoundary` will "win".

**Example JSON Syntax**

```jsx
// Both of these work the same:
const elementRoutes = [{
path: '/',
element: <Home />,
errorElement: <HomeError />,
}]

const componentRoutes = [{
path: '/',
Component: Home,
ErrorBoundary: HomeError,
}]

function Home() { ... }
function HomeError() { ... }
```

**Example JSX Syntax**

```jsx
// Both of these work the same:
const elementRoutes = createRoutesFromElements(
<Route path='/' element={<Home />} errorElement={<HomeError /> } />
);

const elementRoutes = createRoutesFromElements(
<Route path='/' Component={Home} ErrorBoundary={HomeError} />
);

function Home() { ... }
function HomeError() { ... }
```
5 changes: 3 additions & 2 deletions .changeset/lazy-route-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

**Introducing Lazy Route Modules!**

In order to keep your application bundles small and support code-splitting of your routes, we've introduced a new `lazy()` route property. This is an async function that resolves the non-route-matching portions of your route definition (`loader`, `action`, `element`, `errorElement`, etc.). Additionally we've added support for route `Component` and `ErrorBoundary` fields that take precedence over `element`/`errorElement` and make a bit more sense in a statically-defined router as well as when using `route.lazy()`.
In order to keep your application bundles small and support code-splitting of your routes, we've introduced a new `lazy()` route property. This is an async function that resolves the non-route-matching portions of your route definition (`loader`, `action`, `element`/`Component`, `errorElement`/`ErrorBoundary`, `shouldRevalidate`, `handle`).

Lazy routes are resolved on initial load and during the `loading` or `submitting` phase of a navigation or fetcher call. You cannot lazily define route-matching properties (`path`, `index`, `children`) since we only execute your lazy route functions after we've matched known routes.

Expand All @@ -33,7 +33,7 @@ export async function loader({ request }) {
return json(data);
}

// Export a `Component` directly instead of needing to create a React element from it
// Export a `Component` directly instead of needing to create a React Element from it
export function Component() {
let data = useLoaderData();

Expand All @@ -45,6 +45,7 @@ export function Component() {
);
}

// Export an `ErrorBoundary` directly instead of needing to create a React Element from it
export function ErrorBoundary() {
let error = useRouteError();
return isRouteErrorResponse(error) ? (
Expand Down
14 changes: 6 additions & 8 deletions decisions/0002-lazy-route-modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,18 @@ Given what we learned from the original POC, we felt we could do this a bit lean

This proved to work out quite well as we did our own POC so we went with this approach in the end. Now, any time we enter a `submitting`/`loading` state we first check for a `route.lazy` definition and resolve that promise first and update the internal route definition with the result.

The resulting API looks like this, assuming you want to load your homepage in the main bundle, but lazily load the code for the `/about` route:
The resulting API looks like this, assuming you want to load your homepage in the main bundle, but lazily load the code for the `/about` route. Note we're using the new `Component` API introduced along with this work.

```jsx
// app.jsx
const router = createBrowserRouter([
{
path: "/",
element: <Layout />,
Component: Layout,
children: [
{
index: true,
element: <Home />,
Component: Home,
},
{
path: "about",
Expand All @@ -79,9 +79,7 @@ And then your `about.jsx` file would export the properties to be lazily defined
// about.jsx
export function loader() { ... }

export const element = <Component />

function Component() { ... }
export function Component() { ... }
```

## Choices
Expand All @@ -95,7 +93,7 @@ A route has 3 types of fields defined on it:
- Path matching properties: `path`, `index`, `caseSensitive` and `children`
- While not strictly used for matching, `id` is also considered static since it is needed up-front to uniquely identify all defined routes
- Data loading properties: `loader`, `action`, `hasErrorBoundary`, `shouldRevalidate`
- Rendering properties: `handle` and the framework-aware `element`/`errorElement`
- Rendering properties: `handle` and the framework-aware `element`/`errorElement`/`Component`/`ErrorBoundary`

The `route.lazy()` method is focused on lazy-loading the data loading and rendering properties, but cannot update the path matching properties because we have to path match _first_ before we can even identify which matched routes include a `lazy()` function. Therefore, we do not allow path matching route keys to be updated by `lazy()`, and will log a warning if you return one of those properties from your lazy() method.

Expand Down Expand Up @@ -177,7 +175,7 @@ const routes = [
];
```

So in the end, the work for `lazy()` introduced support for `route.Component` and `route.ErrorBoundary`, which can be statically or lazily defined. `element`/`errorElement` will be considered deprecated in data routers and may go away in version 7.
So in the end, the work for `lazy()` introduced support for `route.Component` and `route.ErrorBoundary`, which can be statically or lazily defined. They will take precedence over `element`/`errorElement` if both happen to be defined, but for now both are acceptable ways to define routes. We think we'll be expanding the `Component` API in the future for stronger type-safety since we can pass it inferred-type `loaderData` etc. so in the future that _may_ become the preferred API.

### Interruptions

Expand Down
4 changes: 2 additions & 2 deletions packages/react-router-dom/server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
Router as RemixRouter,
StaticHandlerContext,
CreateStaticHandlerOptions as RouterCreateStaticHandlerOptions,
UNSAFE_RouteManifest,
UNSAFE_RouteManifest as RouteManifest,
} from "@remix-run/router";
import {
IDLE_BLOCKER,
Expand Down Expand Up @@ -227,7 +227,7 @@ export function createStaticRouter(
routes: RouteObject[],
context: StaticHandlerContext
): RemixRouter {
let manifest: UNSAFE_RouteManifest = {};
let manifest: RouteManifest = {};
let dataRoutes = convertRoutesToDataRoutes(
routes,
detectErrorBoundary,
Expand Down

0 comments on commit 2560422

Please sign in to comment.