From fc705d31ede2f79fa26e7f5d3919739820998c68 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 20 Apr 2023 12:45:17 -0400 Subject: [PATCH 1/5] Fix descendant Routes rendering alongside RouterProvider errors --- .changeset/descendant-routes-data-errors.md | 5 ++ .../__tests__/data-memory-router-test.tsx | 55 +++++++++++++++++-- packages/react-router/lib/hooks.tsx | 12 +++- 3 files changed, 64 insertions(+), 8 deletions(-) create mode 100644 .changeset/descendant-routes-data-errors.md diff --git a/.changeset/descendant-routes-data-errors.md b/.changeset/descendant-routes-data-errors.md new file mode 100644 index 0000000000..0d1949df3c --- /dev/null +++ b/.changeset/descendant-routes-data-errors.md @@ -0,0 +1,5 @@ +--- +"react-router": patch +--- + +Fix bug preventing rendering of descendant `` when `RouterProvider` errors existed diff --git a/packages/react-router/__tests__/data-memory-router-test.tsx b/packages/react-router/__tests__/data-memory-router-test.tsx index 2aae328224..a10618c00b 100644 --- a/packages/react-router/__tests__/data-memory-router-test.tsx +++ b/packages/react-router/__tests__/data-memory-router-test.tsx @@ -1019,11 +1019,6 @@ describe("createMemoryRouter", () => { ), { initialEntries: ["/deep/path/to/descendant/routes"], - hydrationData: { - loaderData: { - "0-0": "count=1", - }, - }, } ); let { container } = render(); @@ -1058,6 +1053,56 @@ describe("createMemoryRouter", () => { `); }); + it.only("renders alongside a data router ErrorBoundary", () => { + let router = createMemoryRouter( + [ + { + path: "*", + Component() { + return ( + <> + + + Descendant} /> + + + ); + }, + children: [ + { + id: "index", + index: true, + Component: () =>

Child

, + ErrorBoundary() { + return

{(useRouteError() as Error).message}

; + }, + }, + ], + }, + ], + { + initialEntries: ["/"], + hydrationData: { + errors: { + index: new Error("Broken!"), + }, + }, + } + ); + let { container } = render(); + + expect(getHtml(container)).toMatchInlineSnapshot(` + "
+

+ Broken! +

+

+ Descendant +

+
" + `); + }); + describe("errors", () => { it("renders hydration errors on leaf elements using errorElement", async () => { let router = createMemoryRouter( diff --git a/packages/react-router/lib/hooks.tsx b/packages/react-router/lib/hooks.tsx index 4568e09880..7a6740b6a7 100644 --- a/packages/react-router/lib/hooks.tsx +++ b/packages/react-router/lib/hooks.tsx @@ -319,6 +319,7 @@ export function useRoutes( ); let { navigator } = React.useContext(NavigationContext); + let dataRouterContext = React.useContext(DataRouterContext); let dataRouterStateContext = React.useContext(DataRouterStateContext); let { matches: parentMatches } = React.useContext(RouteContext); let routeMatch = parentMatches[parentMatches.length - 1]; @@ -432,7 +433,10 @@ export function useRoutes( }) ), parentMatches, - dataRouterStateContext || undefined + // Only pass along the dataRouterStateContext when we're rendering from the + // RouterProvider layer. If routes is different then we're rendering from + // a descendant tree + dataRouterContext?.router.routes === routes ? dataRouterStateContext : null ); // When a user passes in a `locationArg`, the associated routes need to @@ -613,7 +617,7 @@ function RenderedRoute({ routeContext, match, children }: RenderedRouteProps) { export function _renderMatches( matches: RouteMatch[] | null, parentMatches: RouteMatch[] = [], - dataRouterState?: RemixRouter["state"] + dataRouterState: RemixRouter["state"] | null = null ): React.ReactElement | null { if (matches == null) { if (dataRouterState?.errors) { @@ -635,7 +639,9 @@ export function _renderMatches( ); invariant( errorIndex >= 0, - `Could not find a matching route for the current errors: ${errors}` + `Could not find a matching route for errors on route IDs: ${Object.keys( + errors + ).join(",")}` ); renderedMatches = renderedMatches.slice( 0, From f1d1e936d664add79b0adae5bba533c7dc7132eb Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 20 Apr 2023 14:51:36 -0400 Subject: [PATCH 2/5] Remove it.only --- .../__tests__/data-memory-router-test.tsx | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/react-router/__tests__/data-memory-router-test.tsx b/packages/react-router/__tests__/data-memory-router-test.tsx index a10618c00b..1f67ec2384 100644 --- a/packages/react-router/__tests__/data-memory-router-test.tsx +++ b/packages/react-router/__tests__/data-memory-router-test.tsx @@ -1053,7 +1053,7 @@ describe("createMemoryRouter", () => { `); }); - it.only("renders alongside a data router ErrorBoundary", () => { + it("renders alongside a data router ErrorBoundary", () => { let router = createMemoryRouter( [ { @@ -1806,14 +1806,14 @@ describe("createMemoryRouter", () => { 💿 Hey developer 👋

- You can provide a way better UX than this when your app throws errors by providing your own + You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or - + @@ -1925,14 +1925,14 @@ describe("createMemoryRouter", () => { 💿 Hey developer 👋

- You can provide a way better UX than this when your app throws errors by providing your own + You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or - + @@ -2159,14 +2159,14 @@ describe("createMemoryRouter", () => { 💿 Hey developer 👋

- You can provide a way better UX than this when your app throws errors by providing your own + You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or - + @@ -2345,14 +2345,14 @@ describe("createMemoryRouter", () => { 💿 Hey developer 👋

- You can provide a way better UX than this when your app throws errors by providing your own + You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or - + From 90a1851fc8e278016c8e5917a697998a6e3819e9 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 20 Apr 2023 15:10:42 -0400 Subject: [PATCH 3/5] Remove fork from Routes in favor of new DataRoutes component --- packages/react-router-dom/server.tsx | 19 ++++++++++++++++--- packages/react-router/lib/components.tsx | 24 ++++++++++++++---------- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/packages/react-router-dom/server.tsx b/packages/react-router-dom/server.tsx index e89006e066..8b21110069 100644 --- a/packages/react-router-dom/server.tsx +++ b/packages/react-router-dom/server.tsx @@ -18,12 +18,17 @@ import { UNSAFE_convertRoutesToDataRoutes as convertRoutesToDataRoutes, } from "@remix-run/router"; import { UNSAFE_mapRouteProperties as mapRouteProperties } from "react-router"; -import type { Location, RouteObject, To } from "react-router-dom"; -import { Routes } from "react-router-dom"; +import type { + DataRouteObject, + Location, + RouteObject, + To, +} from "react-router-dom"; import { createPath, parsePath, Router, + useRoutes, UNSAFE_DataRouterContext as DataRouterContext, UNSAFE_DataRouterStateContext as DataRouterStateContext, } from "react-router-dom"; @@ -127,7 +132,7 @@ export function StaticRouterProvider({ navigationType={dataRouterContext.router.state.historyAction} navigator={dataRouterContext.navigator} > - + @@ -142,6 +147,14 @@ export function StaticRouterProvider({ ); } +function DataRoutes({ + routes, +}: { + routes: DataRouteObject[]; +}): React.ReactElement | null { + return useRoutes(routes); +} + function serializeErrors( errors: StaticHandlerContext["errors"] ): StaticHandlerContext["errors"] { diff --git a/packages/react-router/lib/components.tsx b/packages/react-router/lib/components.tsx index 7cdd4c083b..e5c9949dc8 100644 --- a/packages/react-router/lib/components.tsx +++ b/packages/react-router/lib/components.tsx @@ -116,7 +116,11 @@ export function RouterProvider({ navigationType={router.state.historyAction} navigator={navigator} > - {router.state.initialized ? : fallbackElement} + {router.state.initialized ? ( + + ) : ( + fallbackElement + )} @@ -125,6 +129,14 @@ export function RouterProvider({ ); } +function DataRoutes({ + routes, +}: { + routes: DataRouteObject[]; +}): React.ReactElement | null { + return useRoutes(routes); +} + export interface MemoryRouterProps { basename?: string; children?: React.ReactNode; @@ -393,15 +405,7 @@ export function Routes({ children, location, }: RoutesProps): React.ReactElement | null { - let dataRouterContext = React.useContext(DataRouterContext); - // When in a DataRouterContext _without_ children, we use the router routes - // directly. If we have children, then we're in a descendant tree and we - // need to use child routes. - let routes = - dataRouterContext && !children - ? (dataRouterContext.router.routes as DataRouteObject[]) - : createRoutesFromChildren(children); - return useRoutes(routes, location); + return useRoutes(createRoutesFromChildren(children), location); } export interface AwaitResolveRenderFunction { From 146237abda96bff9cd83384be500466417524b1f Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 20 Apr 2023 15:11:17 -0400 Subject: [PATCH 4/5] Revert whitespace snapshot changes --- .../__tests__/data-memory-router-test.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/react-router/__tests__/data-memory-router-test.tsx b/packages/react-router/__tests__/data-memory-router-test.tsx index 1f67ec2384..95ceccb183 100644 --- a/packages/react-router/__tests__/data-memory-router-test.tsx +++ b/packages/react-router/__tests__/data-memory-router-test.tsx @@ -1806,14 +1806,14 @@ describe("createMemoryRouter", () => { 💿 Hey developer 👋

- You can provide a way better UX than this when your app throws errors by providing your own + You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or - + @@ -1925,14 +1925,14 @@ describe("createMemoryRouter", () => { 💿 Hey developer 👋

- You can provide a way better UX than this when your app throws errors by providing your own + You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or - + @@ -2159,14 +2159,14 @@ describe("createMemoryRouter", () => { 💿 Hey developer 👋

- You can provide a way better UX than this when your app throws errors by providing your own + You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or - + @@ -2345,14 +2345,14 @@ describe("createMemoryRouter", () => { 💿 Hey developer 👋

- You can provide a way better UX than this when your app throws errors by providing your own + You can provide a way better UX than this when your app throws errors by providing your own ErrorBoundary or - + From 8602a25ad2f04cd70f14d11f0c8a9b3e68835264 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 20 Apr 2023 15:21:54 -0400 Subject: [PATCH 5/5] bump bundle --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8b95a2d15f..fb87fd7997 100644 --- a/package.json +++ b/package.json @@ -108,10 +108,10 @@ "none": "45 kB" }, "packages/react-router/dist/react-router.production.min.js": { - "none": "13.3 kB" + "none": "13.4 kB" }, "packages/react-router/dist/umd/react-router.production.min.js": { - "none": "15.6 kB" + "none": "15.7 kB" }, "packages/react-router-dom/dist/react-router-dom.production.min.js": { "none": "11.8 kB"