Skip to content

Commit 04ce64a

Browse files
committed
Make the implementation more readable.
1 parent 3404ea4 commit 04ce64a

File tree

2 files changed

+96
-45
lines changed

2 files changed

+96
-45
lines changed

dev-packages/e2e-tests/test-applications/react-router-7-lazy-routes/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"name": "react-router-7-cross-usage",
2+
"name": "react-router-7-lazy-routes",
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {

packages/react/src/reactrouterv6-compat-utils.tsx

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -64,54 +64,105 @@ type V6CompatibleVersion = '6' | '7';
6464
const allRoutes = new Set<RouteObject>();
6565

6666
/**
67-
* Recursively checks a route for async handlers and sets up Proxies to add discovered child routes to allRoutes when called.
67+
* Handles the result of an async handler function call.
6868
*/
69-
export function checkRouteForAsyncHandler(route: RouteObject): void {
70-
// If the route has a handle, set up proxies for any functions on it
71-
if (route.handle && typeof route.handle === 'object') {
72-
for (const key of Object.keys(route.handle)) {
73-
const maybeFn = route.handle[key];
74-
if (typeof maybeFn === 'function') {
75-
// Create a proxy that intercepts function calls
76-
route.handle[key] = new Proxy(maybeFn, {
77-
apply(target, thisArg, argArray) {
78-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
79-
const result = target.apply(thisArg, argArray);
80-
// If the result is a promise, handle it when resolved
81-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
82-
if (result && typeof result.then === 'function') {
83-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
84-
result
85-
.then((resolvedRoutes: unknown) => {
86-
if (Array.isArray(resolvedRoutes)) {
87-
// Add resolved routes as children to maintain proper route tree structure
88-
route.children = resolvedRoutes;
89-
// Add discovered children to allRoutes
90-
resolvedRoutes.forEach(child => {
91-
allRoutes.add(child);
92-
// Recursively check for async handlers in child routes
93-
checkRouteForAsyncHandler(child);
94-
});
95-
}
96-
})
97-
.catch((e: unknown) => {
98-
DEBUG_BUILD && debug.warn(`Error resolving async handler '${key}' for route`, route, e);
99-
});
100-
} else if (Array.isArray(result)) {
101-
// Handle synchronous array results - add as children to maintain route tree structure
102-
route.children = result;
103-
result.forEach(child => {
104-
allRoutes.add(child);
105-
checkRouteForAsyncHandler(child);
106-
});
107-
}
108-
return result;
109-
},
110-
});
69+
function handleAsyncHandlerResult(result: unknown, route: RouteObject, handlerKey: string): void {
70+
if (
71+
result &&
72+
typeof result === 'object' &&
73+
'then' in result &&
74+
typeof (result as Promise<unknown>).then === 'function'
75+
) {
76+
handlePromiseResult(result as Promise<unknown>, route, handlerKey);
77+
} else if (Array.isArray(result)) {
78+
handleSynchronousArrayResult(result, route);
79+
}
80+
}
81+
82+
/**
83+
* Handles promise results from async handlers.
84+
*/
85+
function handlePromiseResult(promise: Promise<unknown>, route: RouteObject, handlerKey: string): void {
86+
promise
87+
.then((resolvedRoutes: unknown) => {
88+
if (Array.isArray(resolvedRoutes)) {
89+
addResolvedRoutesToParent(resolvedRoutes, route);
90+
processResolvedRoutes(resolvedRoutes);
11191
}
92+
})
93+
.catch((e: unknown) => {
94+
DEBUG_BUILD && debug.warn(`Error resolving async handler '${handlerKey}' for route`, route, e);
95+
});
96+
}
97+
98+
/**
99+
* Handles synchronous array results from handlers.
100+
*/
101+
function handleSynchronousArrayResult(result: RouteObject[], route: RouteObject): void {
102+
addResolvedRoutesToParent(result, route);
103+
processResolvedRoutes(result);
104+
}
105+
106+
/**
107+
* Adds resolved routes as children to the parent route.
108+
*/
109+
function addResolvedRoutesToParent(resolvedRoutes: RouteObject[], parentRoute: RouteObject): void {
110+
parentRoute.children = Array.isArray(parentRoute.children)
111+
? [...parentRoute.children, ...resolvedRoutes]
112+
: resolvedRoutes;
113+
}
114+
115+
/**
116+
* Processes resolved routes by adding them to allRoutes and checking for nested async handlers.
117+
*/
118+
function processResolvedRoutes(resolvedRoutes: RouteObject[]): void {
119+
resolvedRoutes.forEach(child => {
120+
allRoutes.add(child);
121+
checkRouteForAsyncHandler(child);
122+
});
123+
}
124+
125+
/**
126+
* Creates a proxy wrapper for an async handler function.
127+
*/
128+
function createAsyncHandlerProxy(
129+
originalFunction: (...args: unknown[]) => unknown,
130+
route: RouteObject,
131+
handlerKey: string,
132+
): (...args: unknown[]) => unknown {
133+
return new Proxy(originalFunction, {
134+
apply(target: (...args: unknown[]) => unknown, thisArg, argArray) {
135+
const result = target.apply(thisArg, argArray);
136+
handleAsyncHandlerResult(result, route, handlerKey);
137+
return result;
138+
},
139+
});
140+
}
141+
142+
/**
143+
* Sets up proxies for all function properties in a route's handle object.
144+
*/
145+
function setupHandleProxies(route: RouteObject): void {
146+
if (!route.handle || typeof route.handle !== 'object') {
147+
return;
148+
}
149+
150+
for (const key of Object.keys(route.handle)) {
151+
const maybeFn = route.handle[key];
152+
if (typeof maybeFn === 'function') {
153+
route.handle[key] = createAsyncHandlerProxy(maybeFn, route, key);
112154
}
113155
}
114-
// If the route has children, check them recursively
156+
}
157+
158+
/**
159+
* Recursively checks a route for async handlers and sets up Proxies to add discovered child routes to allRoutes when called.
160+
*/
161+
export function checkRouteForAsyncHandler(route: RouteObject): void {
162+
// Set up proxies for any functions in the route's handle
163+
setupHandleProxies(route);
164+
165+
// Recursively check child routes
115166
if (Array.isArray(route.children)) {
116167
for (const child of route.children) {
117168
checkRouteForAsyncHandler(child);

0 commit comments

Comments
 (0)