@@ -271,7 +271,13 @@ export function getRSCSingleFetchDataStrategy(
271
271
// pass map into fetchAndDecode so it can add payloads
272
272
getFetchAndDecodeViaRSC ( decode ) ,
273
273
ssr ,
274
- basename
274
+ basename ,
275
+ // If we don't have an element, we need to hit the server loader flow
276
+ // regardless of whether the client loader calls `serverLoader` or not,
277
+ // otherwise we'll have nothing to render.
278
+ // TODO: Do we need to account for API routes? Do we need a
279
+ // `match.hasComponent` flag?
280
+ ( match ) => match . route . element != null
275
281
) ;
276
282
return async ( args ) =>
277
283
args . unstable_runClientMiddleware ( async ( ) => {
@@ -288,17 +294,27 @@ export function getRSCSingleFetchDataStrategy(
288
294
context . set ( renderedRoutesContext , [ ] ) ;
289
295
let results = await dataStrategy ( args ) ;
290
296
// patch into router from all payloads in map
291
- const renderedRouteById = new Map (
292
- context . get ( renderedRoutesContext ) . map ( ( r ) => [ r . id , r ] )
293
- ) ;
297
+ // TODO: Confirm that it's correct for us to have multiple rendered routes
298
+ // with the same ID. This is currently happening in `clientLoader` cases
299
+ // where we're calling `fetchAndDecode` multiple times. This may be a
300
+ // sign of a logical error in how we're handling client loader routes.
301
+ const renderedRoutesById = new Map < string , RenderedRoute [ ] > ( ) ;
302
+ for ( const route of context . get ( renderedRoutesContext ) ) {
303
+ if ( ! renderedRoutesById . has ( route . id ) ) {
304
+ renderedRoutesById . set ( route . id , [ ] ) ;
305
+ }
306
+ renderedRoutesById . get ( route . id ) ! . push ( route ) ;
307
+ }
294
308
for ( const match of args . matches ) {
295
- const rendered = renderedRouteById . get ( match . route . id ) ;
296
- if ( rendered ) {
297
- window . __router . patchRoutes (
298
- rendered . parentId ?? null ,
299
- [ createRouteFromServerManifest ( rendered ) ] ,
300
- true
301
- ) ;
309
+ const renderedRoutes = renderedRoutesById . get ( match . route . id ) ;
310
+ if ( renderedRoutes ) {
311
+ for ( const rendered of renderedRoutes ) {
312
+ window . __router . patchRoutes (
313
+ rendered . parentId ?? null ,
314
+ [ createRouteFromServerManifest ( rendered ) ] ,
315
+ true
316
+ ) ;
317
+ }
302
318
}
303
319
}
304
320
return results ;
@@ -457,7 +473,14 @@ function createRouteFromServerManifest(
457
473
let hasInitialError = payload ?. errors && match . id in payload . errors ;
458
474
let initialError = payload ?. errors ?. [ match . id ] ;
459
475
let isHydrationRequest =
460
- match . clientLoader ?. hydrate === true || ! match . hasLoader ;
476
+ match . clientLoader ?. hydrate === true ||
477
+ ! match . hasLoader ||
478
+ // If we don't have an element, we need to hit the server loader flow
479
+ // regardless of whether the client loader calls `serverLoader` or not,
480
+ // otherwise we'll have nothing to render.
481
+ // TODO: Do we need to account for API routes? Do we need a
482
+ // `match.hasComponent` flag?
483
+ ! match . element ;
461
484
462
485
let dataRoute : DataRouteObjectWithManifestInfo = {
463
486
id : match . id ,
0 commit comments