@@ -58,6 +58,7 @@ import type {
5858} from "./types/route-data" ;
5959import type { unstable_ClientOnErrorFunction } from "./components" ;
6060import type { RouteModules } from "./types/register" ;
61+ import { decodeRedirectErrorDigest } from "./errors" ;
6162
6263/**
6364 * Resolves a URL against the current {@link Location}.
@@ -758,6 +759,7 @@ export function useRoutesImpl(
758759 locationArg ?: Partial < Location > | string ,
759760 dataRouterState ?: DataRouter [ "state" ] ,
760761 unstable_onError ?: unstable_ClientOnErrorFunction ,
762+ unstable_rsc ?: boolean ,
761763 future ?: DataRouter [ "future" ] ,
762764) : React . ReactElement | null {
763765 invariant (
@@ -912,6 +914,7 @@ export function useRoutesImpl(
912914 parentMatches ,
913915 dataRouterState ,
914916 unstable_onError ,
917+ unstable_rsc ,
915918 future ,
916919 ) ;
917920
@@ -991,6 +994,7 @@ type RenderErrorBoundaryProps = React.PropsWithChildren<{
991994 component : React . ReactNode ;
992995 routeContext : RouteContextObject ;
993996 onError ?: ( error : unknown , errorInfo ?: React . ErrorInfo ) => void ;
997+ unstable_rsc ?: boolean ;
994998} > ;
995999
9961000type RenderErrorBoundaryState = {
@@ -1062,17 +1066,56 @@ export class RenderErrorBoundary extends React.Component<
10621066 }
10631067
10641068 render ( ) {
1065- return this . state . error !== undefined ? (
1066- < RouteContext . Provider value = { this . props . routeContext } >
1067- < RouteErrorContext . Provider
1068- value = { this . state . error }
1069- children = { this . props . component }
1070- />
1071- </ RouteContext . Provider >
1072- ) : (
1073- this . props . children
1074- ) ;
1069+ let result =
1070+ this . state . error !== undefined ? (
1071+ < RouteContext . Provider value = { this . props . routeContext } >
1072+ < RouteErrorContext . Provider
1073+ value = { this . state . error }
1074+ children = { this . props . component }
1075+ />
1076+ </ RouteContext . Provider >
1077+ ) : (
1078+ this . props . children
1079+ ) ;
1080+
1081+ if ( this . props . unstable_rsc ) {
1082+ return (
1083+ < RSCErrorHandler error = { this . state . error } > { result } </ RSCErrorHandler >
1084+ ) ;
1085+ }
1086+
1087+ return result ;
1088+ }
1089+ }
1090+
1091+ const errorRedirectPromises = new WeakMap < any , Promise < void > > ( ) ;
1092+ function RSCErrorHandler ( {
1093+ children,
1094+ error,
1095+ } : {
1096+ children : React . ReactNode ;
1097+ error : unknown ;
1098+ } ) {
1099+ if (
1100+ typeof error === "object" &&
1101+ error &&
1102+ "digest" in error &&
1103+ typeof error . digest === "string"
1104+ ) {
1105+ let redirect = decodeRedirectErrorDigest ( error . digest ) ;
1106+ if ( redirect ) {
1107+ let promise = errorRedirectPromises . get ( error ) ;
1108+ if ( ! promise ) {
1109+ // TODO: Handle external redirects?
1110+ promise = window . __reactRouterDataRouter ! . navigate ( redirect . location , {
1111+ replace : true ,
1112+ } ) ;
1113+ errorRedirectPromises . set ( error , promise ) ;
1114+ }
1115+ throw promise ;
1116+ }
10751117 }
1118+ return children ;
10761119}
10771120
10781121interface RenderedRouteProps {
@@ -1107,6 +1150,7 @@ export function _renderMatches(
11071150 parentMatches : RouteMatch [ ] = [ ] ,
11081151 dataRouterState : DataRouter [ "state" ] | null = null ,
11091152 unstable_onError : unstable_ClientOnErrorFunction | null = null ,
1153+ unstable_rsc : boolean | undefined = undefined ,
11101154 future : DataRouter [ "future" ] | null = null ,
11111155) : React . ReactElement | null {
11121156 if ( matches == null ) {
@@ -1275,6 +1319,7 @@ export function _renderMatches(
12751319 error = { error }
12761320 children = { getChildren ( ) }
12771321 routeContext = { { outlet : null , matches, isDataRoute : true } }
1322+ unstable_rsc = { unstable_rsc }
12781323 onError = { onError }
12791324 />
12801325 ) : (
0 commit comments