File tree Expand file tree Collapse file tree 3 files changed +100
-0
lines changed
Expand file tree Collapse file tree 3 files changed +100
-0
lines changed Original file line number Diff line number Diff line change 1+ ---
2+ " react-router " : patch
3+ ---
4+
5+ Handle ` dataStrategy ` implementations that return insufficient result sets by adding errors for routes without any available result
Original file line number Diff line number Diff line change 77} from "@testing-library/react" ;
88import * as React from "react" ;
99import type {
10+ DataStrategyResult ,
1011 ErrorResponse ,
1112 Fetcher ,
1213 Location ,
@@ -420,6 +421,78 @@ function testDomRouter(
420421 </div>"
421422 ` ) ;
422423 } ) ;
424+
425+ it ( "clears the HydrateFallback when dataStrategy returns partial results during hydration" , async ( ) => {
426+ let dfd = createDeferred < Record < string , DataStrategyResult > > ( ) ;
427+ let router = createTestRouter (
428+ [
429+ {
430+ id : "root" ,
431+ path : "/" ,
432+ loader : true ,
433+ HydrateFallback : ( ) => "Loading..." ,
434+ Component : ( ) => (
435+ < >
436+ < h1 > Root:{ useLoaderData ( ) } </ h1 >
437+ < Outlet />
438+ </ >
439+ ) ,
440+ ErrorBoundary : ( ) => {
441+ let error = useRouteError ( ) ;
442+ return (
443+ < pre >
444+ Root:
445+ { error instanceof Error ? error . message : ( error as string ) }
446+ </ pre >
447+ ) ;
448+ } ,
449+ children : [
450+ {
451+ id : "index" ,
452+ index : true ,
453+ loader : true ,
454+ Component : ( ) => < h2 > Index:{ useLoaderData ( ) } </ h2 > ,
455+ ErrorBoundary : ( ) => (
456+ < pre > Index:{ useRouteError ( ) as string } </ pre >
457+ ) ,
458+ } ,
459+ ] ,
460+ } ,
461+ ] ,
462+ {
463+ dataStrategy : ( ) => dfd . promise ,
464+ } ,
465+ ) ;
466+ let { container } = render ( < RouterProvider router = { router } /> ) ;
467+
468+ expect ( getHtml ( container ) ) . toMatchInlineSnapshot ( `
469+ "<div>
470+ Loading...
471+ </div>"
472+ ` ) ;
473+
474+ // Resolve data strategy with only an error at the index route but nothing
475+ // for the root route
476+ await dfd . resolve ( {
477+ index : {
478+ type : "error" ,
479+ result : "INDEX ERROR" ,
480+ } ,
481+ } ) ;
482+ await tick ( ) ;
483+ await tick ( ) ;
484+
485+ // The router stubs in an error for the root route to get out of
486+ // displaying the HydrateFallback
487+ expect ( getHtml ( container ) ) . toMatchInlineSnapshot ( `
488+ "<div>
489+ <pre>
490+ Root:
491+ No result returned from dataStrategy for route root
492+ </pre>
493+ </div>"
494+ ` ) ;
495+ } ) ;
423496 } ) ;
424497
425498 describe ( "navigations" , ( ) => {
Original file line number Diff line number Diff line change @@ -3032,6 +3032,28 @@ export function createRouter(init: RouterInit): Router {
30323032 return dataResults ;
30333033 }
30343034
3035+ // If they forgot to return a result for a match, and we don't have existing
3036+ // `loaderData`/`errors` for that match, then we add an error to trigger the
3037+ // error boundary since we don't have any `loaderData` and therefore can't
3038+ // render the `Component`
3039+ if ( ! isMutationMethod ( request . method ) ) {
3040+ for ( let match of matches ) {
3041+ if (
3042+ match . shouldCallHandler ( ) &&
3043+ ! results . hasOwnProperty ( match . route . id ) &&
3044+ ! state . loaderData . hasOwnProperty ( match . route . id ) &&
3045+ ( ! state . errors || ! state . errors . hasOwnProperty ( match . route . id ) )
3046+ ) {
3047+ results [ match . route . id ] = {
3048+ type : ResultType . error ,
3049+ result : new Error (
3050+ `No result returned from dataStrategy for route ${ match . route . id } ` ,
3051+ ) ,
3052+ } ;
3053+ }
3054+ }
3055+ }
3056+
30353057 for ( let [ routeId , result ] of Object . entries ( results ) ) {
30363058 if ( isRedirectDataStrategyResult ( result ) ) {
30373059 let response = result . result as Response ;
You can’t perform that action at this time.
0 commit comments