Skip to content

Commit 4a0ca63

Browse files
committed
Stabilize client-side onError
1 parent 4789692 commit 4a0ca63

File tree

7 files changed

+50
-48
lines changed

7 files changed

+50
-48
lines changed

.changeset/small-flowers-drive.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": minor
3+
---
4+
5+
Stabilize `<HydratedRouter onError>`/`<RouterProvider onError>`

integration/browser-entry-test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ test("allows users to pass an onError function to HydratedRouter", async ({
146146
document,
147147
<StrictMode>
148148
<HydratedRouter
149-
unstable_onError={(error, errorInfo) => {
149+
onError={(error, errorInfo) => {
150150
console.log(error.message, JSON.stringify(errorInfo))
151151
}}
152152
/>

packages/react-router/__tests__/dom/client-on-error-test.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe(`handleError`, () => {
4444
]);
4545

4646
let { container } = render(
47-
<RouterProvider router={router} unstable_onError={spy} />,
47+
<RouterProvider router={router} onError={spy} />,
4848
);
4949
await waitFor(() => screen.getByText("lazy error!"));
5050

@@ -74,7 +74,7 @@ describe(`handleError`, () => {
7474
},
7575
]);
7676

77-
render(<RouterProvider router={router} unstable_onError={spy} />);
77+
render(<RouterProvider router={router} onError={spy} />);
7878

7979
await waitFor(() => screen.getByText("Error:middleware error!"));
8080

@@ -102,7 +102,7 @@ describe(`handleError`, () => {
102102
},
103103
]);
104104

105-
render(<RouterProvider router={router} unstable_onError={spy} />);
105+
render(<RouterProvider router={router} onError={spy} />);
106106

107107
await waitFor(() => screen.getByText("Error:loader error!"));
108108

@@ -131,7 +131,7 @@ describe(`handleError`, () => {
131131
]);
132132

133133
let { container } = render(
134-
<RouterProvider router={router} unstable_onError={spy} />,
134+
<RouterProvider router={router} onError={spy} />,
135135
);
136136

137137
await act(() => router.navigate("/page"));
@@ -166,7 +166,7 @@ describe(`handleError`, () => {
166166
]);
167167

168168
let { container } = render(
169-
<RouterProvider router={router} unstable_onError={spy} />,
169+
<RouterProvider router={router} onError={spy} />,
170170
);
171171

172172
await act(() => router.navigate("/page"));
@@ -197,7 +197,7 @@ describe(`handleError`, () => {
197197
]);
198198

199199
let { container } = render(
200-
<RouterProvider router={router} unstable_onError={spy} />,
200+
<RouterProvider router={router} onError={spy} />,
201201
);
202202

203203
await act(() => router.navigate("/page"));
@@ -228,7 +228,7 @@ describe(`handleError`, () => {
228228
]);
229229

230230
let { container } = render(
231-
<RouterProvider router={router} unstable_onError={spy} />,
231+
<RouterProvider router={router} onError={spy} />,
232232
);
233233

234234
await act(() =>
@@ -262,7 +262,7 @@ describe(`handleError`, () => {
262262
]);
263263

264264
let { container } = render(
265-
<RouterProvider router={router} unstable_onError={spy} />,
265+
<RouterProvider router={router} onError={spy} />,
266266
);
267267

268268
await act(() => router.fetch("key", "0", "/fetch"));
@@ -291,7 +291,7 @@ describe(`handleError`, () => {
291291
]);
292292

293293
let { container } = render(
294-
<RouterProvider router={router} unstable_onError={spy} />,
294+
<RouterProvider router={router} onError={spy} />,
295295
);
296296

297297
await act(() =>
@@ -326,7 +326,7 @@ describe(`handleError`, () => {
326326
]);
327327

328328
let { container } = render(
329-
<RouterProvider router={router} unstable_onError={spy} />,
329+
<RouterProvider router={router} onError={spy} />,
330330
);
331331

332332
await act(() => router.navigate("/page"));
@@ -370,7 +370,7 @@ describe(`handleError`, () => {
370370
]);
371371

372372
let { container } = render(
373-
<RouterProvider router={router} unstable_onError={spy} />,
373+
<RouterProvider router={router} onError={spy} />,
374374
);
375375

376376
await act(() => router.navigate("/page"));
@@ -418,7 +418,7 @@ describe(`handleError`, () => {
418418
}
419419

420420
let { container } = render(
421-
<RouterProvider router={router} unstable_onError={spy} />,
421+
<RouterProvider router={router} onError={spy} />,
422422
);
423423

424424
await act(() => router.navigate("/page"));
@@ -472,7 +472,7 @@ describe(`handleError`, () => {
472472
}
473473

474474
let { container } = render(
475-
<RouterProvider router={router} unstable_onError={spy} />,
475+
<RouterProvider router={router} onError={spy} />,
476476
);
477477

478478
await act(() => router.navigate("/page"));
@@ -526,7 +526,7 @@ describe(`handleError`, () => {
526526
]);
527527

528528
let { container } = render(
529-
<RouterProvider router={router} unstable_onError={spy} />,
529+
<RouterProvider router={router} onError={spy} />,
530530
);
531531

532532
await act(() => router.navigate("/page"));
@@ -576,7 +576,7 @@ describe(`handleError`, () => {
576576
]);
577577

578578
let { container } = render(
579-
<RouterProvider router={router} unstable_onError={spy} />,
579+
<RouterProvider router={router} onError={spy} />,
580580
);
581581

582582
await act(() => router.navigate("/page"));

packages/react-router/lib/components.tsx

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -347,13 +347,13 @@ export interface RouterProviderProps {
347347
* and is only present for render errors.
348348
*
349349
* ```tsx
350-
* <RouterProvider unstable_onError=(error, errorInfo) => {
350+
* <RouterProvider onError=(error, errorInfo) => {
351351
* console.error(error, errorInfo);
352352
* reportToErrorService(error, errorInfo);
353353
* }} />
354354
* ```
355355
*/
356-
unstable_onError?: unstable_ClientOnErrorFunction;
356+
onError?: unstable_ClientOnErrorFunction;
357357
}
358358

359359
function shallowDiff(a: any, b: any) {
@@ -376,7 +376,7 @@ function shallowDiff(a: any, b: any) {
376376
export function UNSTABLE_TransitionEnabledRouterProvider({
377377
router,
378378
flushSync: reactDomFlushSyncImpl,
379-
unstable_onError,
379+
onError,
380380
}: RouterProviderProps) {
381381
let fetcherData = React.useRef<Map<string, any>>(new Map());
382382
let [revalidating, startRevalidation] = React.useTransition();
@@ -420,9 +420,9 @@ export function UNSTABLE_TransitionEnabledRouterProvider({
420420
navigator,
421421
static: false,
422422
basename,
423-
unstable_onError,
423+
onError,
424424
}),
425-
[router, navigator, basename, unstable_onError],
425+
[router, navigator, basename, onError],
426426
);
427427

428428
React.useLayoutEffect(() => {
@@ -481,7 +481,7 @@ export function UNSTABLE_TransitionEnabledRouterProvider({
481481
routes={router.routes}
482482
future={router.future}
483483
state={state}
484-
unstable_onError={unstable_onError}
484+
onError={onError}
485485
/>
486486
</Router>
487487
{/* </ViewTransitionContext.Provider> */}
@@ -520,14 +520,14 @@ export function UNSTABLE_TransitionEnabledRouterProvider({
520520
* @mode data
521521
* @param props Props
522522
* @param {RouterProviderProps.flushSync} props.flushSync n/a
523-
* @param {RouterProviderProps.unstable_onError} props.unstable_onError n/a
523+
* @param {RouterProviderProps.onError} props.onError n/a
524524
* @param {RouterProviderProps.router} props.router n/a
525525
* @returns React element for the rendered router
526526
*/
527527
export function RouterProvider({
528528
router,
529529
flushSync: reactDomFlushSyncImpl,
530-
unstable_onError,
530+
onError,
531531
}: RouterProviderProps): React.ReactElement {
532532
let [state, setStateImpl] = React.useState(router.state);
533533
let [pendingState, setPendingState] = React.useState<RouterState>();
@@ -546,10 +546,10 @@ export function RouterProvider({
546546
(newState: RouterState) => {
547547
setStateImpl((prevState) => {
548548
// Send loader/action errors through handleError
549-
if (newState.errors && unstable_onError) {
549+
if (newState.errors && onError) {
550550
Object.entries(newState.errors).forEach(([routeId, error]) => {
551551
if (prevState.errors?.[routeId] !== error) {
552-
unstable_onError(error, {
552+
onError(error, {
553553
location: newState.location,
554554
params: newState.matches[0]?.params ?? {},
555555
});
@@ -559,7 +559,7 @@ export function RouterProvider({
559559
return newState;
560560
});
561561
},
562-
[unstable_onError],
562+
[onError],
563563
);
564564

565565
let setState = React.useCallback<RouterSubscriber>(
@@ -761,9 +761,9 @@ export function RouterProvider({
761761
navigator,
762762
static: false,
763763
basename,
764-
unstable_onError,
764+
onError,
765765
}),
766-
[router, navigator, basename, unstable_onError],
766+
[router, navigator, basename, onError],
767767
);
768768

769769
// The fragment and {null} here are important! We need them to keep React 18's
@@ -788,7 +788,7 @@ export function RouterProvider({
788788
routes={router.routes}
789789
future={router.future}
790790
state={state}
791-
unstable_onError={unstable_onError}
791+
onError={onError}
792792
/>
793793
</Router>
794794
</ViewTransitionContext.Provider>
@@ -807,14 +807,14 @@ function DataRoutes({
807807
routes,
808808
future,
809809
state,
810-
unstable_onError,
810+
onError,
811811
}: {
812812
routes: DataRouteObject[];
813813
future: DataRouter["future"];
814814
state: RouterState;
815-
unstable_onError: unstable_ClientOnErrorFunction | undefined;
815+
onError: unstable_ClientOnErrorFunction | undefined;
816816
}): React.ReactElement | null {
817-
return useRoutesImpl(routes, undefined, state, unstable_onError, future);
817+
return useRoutesImpl(routes, undefined, state, onError, future);
818818
}
819819

820820
/**
@@ -1614,10 +1614,10 @@ export function Await<Resolve>({
16141614
(error: unknown, errorInfo?: React.ErrorInfo) => {
16151615
if (
16161616
dataRouterContext &&
1617-
dataRouterContext.unstable_onError &&
1617+
dataRouterContext.onError &&
16181618
dataRouterStateContext
16191619
) {
1620-
dataRouterContext.unstable_onError(error, {
1620+
dataRouterContext.onError(error, {
16211621
location: dataRouterStateContext.location,
16221622
params: dataRouterStateContext.matches?.[0]?.params || {},
16231623
errorInfo,

packages/react-router/lib/context.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ export interface DataRouterContextObject
9191
extends Omit<NavigationContextObject, "future"> {
9292
router: Router;
9393
staticContext?: StaticHandlerContext;
94-
unstable_onError?: unstable_ClientOnErrorFunction;
94+
onError?: unstable_ClientOnErrorFunction;
9595
}
9696

9797
export const DataRouterContext =

packages/react-router/lib/dom-export/hydrated-router.tsx

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -291,13 +291,13 @@ export interface HydratedRouterProps {
291291
* and is only present for render errors.
292292
*
293293
* ```tsx
294-
* <HydratedRouter unstable_onError={(error, errorInfo) => {
294+
* <HydratedRouter onError={(error, errorInfo) => {
295295
* console.error(error, errorInfo);
296296
* reportToErrorService(error, errorInfo);
297297
* }} />
298298
* ```
299299
*/
300-
unstable_onError?: unstable_ClientOnErrorFunction;
300+
onError?: unstable_ClientOnErrorFunction;
301301
}
302302

303303
/**
@@ -309,7 +309,7 @@ export interface HydratedRouterProps {
309309
* @mode framework
310310
* @param props Props
311311
* @param {dom.HydratedRouterProps.getContext} props.getContext n/a
312-
* @param {dom.HydratedRouterProps.unstable_onError} props.unstable_onError n/a
312+
* @param {dom.HydratedRouterProps.onError} props.onError n/a
313313
* @returns A React element that represents the hydrated application.
314314
*/
315315
export function HydratedRouter(props: HydratedRouterProps) {
@@ -402,10 +402,7 @@ export function HydratedRouter(props: HydratedRouterProps) {
402402
}}
403403
>
404404
<RemixErrorBoundary location={location}>
405-
<RouterProvider
406-
router={router}
407-
unstable_onError={props.unstable_onError}
408-
/>
405+
<RouterProvider router={router} onError={props.onError} />
409406
</RemixErrorBoundary>
410407
</FrameworkContext.Provider>
411408
{/*

packages/react-router/lib/hooks.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -754,7 +754,7 @@ export function useRoutesImpl(
754754
routes: RouteObject[],
755755
locationArg?: Partial<Location> | string,
756756
dataRouterState?: DataRouter["state"],
757-
unstable_onError?: unstable_ClientOnErrorFunction,
757+
onError?: unstable_ClientOnErrorFunction,
758758
future?: DataRouter["future"],
759759
): React.ReactElement | null {
760760
invariant(
@@ -908,7 +908,7 @@ export function useRoutesImpl(
908908
),
909909
parentMatches,
910910
dataRouterState,
911-
unstable_onError,
911+
onError,
912912
future,
913913
);
914914

@@ -1103,7 +1103,7 @@ export function _renderMatches(
11031103
matches: RouteMatch[] | null,
11041104
parentMatches: RouteMatch[] = [],
11051105
dataRouterState: DataRouter["state"] | null = null,
1106-
unstable_onError: unstable_ClientOnErrorFunction | null = null,
1106+
onErrorHandler: unstable_ClientOnErrorFunction | null = null,
11071107
future: DataRouter["future"] | null = null,
11081108
): React.ReactElement | null {
11091109
if (matches == null) {
@@ -1187,9 +1187,9 @@ export function _renderMatches(
11871187
}
11881188

11891189
let onError =
1190-
dataRouterState && unstable_onError
1190+
dataRouterState && onErrorHandler
11911191
? (error: unknown, errorInfo?: React.ErrorInfo) => {
1192-
unstable_onError(error, {
1192+
onErrorHandler(error, {
11931193
location: dataRouterState.location,
11941194
params: dataRouterState.matches?.[0]?.params ?? {},
11951195
errorInfo,

0 commit comments

Comments
 (0)