Skip to content

Commit 5d7b373

Browse files
committed
Fix single fetch revalidation bug on reused routes
1 parent 54147a3 commit 5d7b373

File tree

3 files changed

+99
-3
lines changed

3 files changed

+99
-3
lines changed

.changeset/fair-weeks-beam.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router": patch
3+
---
4+
5+
Fix single fetch bug where no revalidation request would be made when navigating upwards to a reused parent route

packages/react-router/__tests__/router/data-strategy-test.ts

+86
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,92 @@ describe("router dataStrategy", () => {
568568
child: "CHILD",
569569
});
570570
});
571+
572+
it("does not short circuit when there are no matchesToLoad", async () => {
573+
let dataStrategy = mockDataStrategy(async ({ matches }) => {
574+
let results = await Promise.all(
575+
matches.map((m) => m.resolve((handler) => handler()))
576+
);
577+
// Don't use keyedResults since it checks for shouldLoad and this test
578+
// is always loading
579+
return results.reduce(
580+
(acc, r, i) => Object.assign(acc, { [matches[i].route.id]: r }),
581+
{}
582+
);
583+
});
584+
let t = setup({
585+
routes: [
586+
{
587+
path: "/",
588+
},
589+
{
590+
id: "parent",
591+
path: "/parent",
592+
loader: true,
593+
children: [
594+
{
595+
id: "child",
596+
path: "child",
597+
loader: true,
598+
},
599+
],
600+
},
601+
],
602+
dataStrategy,
603+
});
604+
605+
let A = await t.navigate("/parent");
606+
await A.loaders.parent.resolve("PARENT1");
607+
expect(A.loaders.parent.stub).toHaveBeenCalled();
608+
expect(t.router.state.loaderData).toEqual({
609+
parent: "PARENT1",
610+
});
611+
expect(dataStrategy.mock.calls[0][0].matches).toEqual([
612+
expect.objectContaining({
613+
route: expect.objectContaining({
614+
id: "parent",
615+
}),
616+
}),
617+
]);
618+
619+
let B = await t.navigate("/parent/child");
620+
await B.loaders.parent.resolve("PARENT2");
621+
await B.loaders.child.resolve("CHILD");
622+
expect(B.loaders.parent.stub).toHaveBeenCalled();
623+
expect(B.loaders.child.stub).toHaveBeenCalled();
624+
expect(t.router.state.loaderData).toEqual({
625+
parent: "PARENT2",
626+
child: "CHILD",
627+
});
628+
expect(dataStrategy.mock.calls[1][0].matches).toEqual([
629+
expect.objectContaining({
630+
route: expect.objectContaining({
631+
id: "parent",
632+
}),
633+
}),
634+
expect.objectContaining({
635+
route: expect.objectContaining({
636+
id: "child",
637+
}),
638+
}),
639+
]);
640+
641+
let C = await t.navigate("/parent");
642+
await C.loaders.parent.resolve("PARENT3");
643+
expect(C.loaders.parent.stub).toHaveBeenCalled();
644+
expect(t.router.state.loaderData).toEqual({
645+
parent: "PARENT3",
646+
});
647+
expect(dataStrategy.mock.calls[2][0].matches).toEqual([
648+
expect.objectContaining({
649+
route: expect.objectContaining({
650+
id: "parent",
651+
}),
652+
}),
653+
]);
654+
655+
expect(dataStrategy).toHaveBeenCalledTimes(3);
656+
});
571657
});
572658

573659
describe("actions", () => {

packages/react-router/lib/router/router.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -1927,8 +1927,13 @@ export function createRouter(init: RouterInit): Router {
19271927

19281928
pendingNavigationLoadId = ++incrementingLoadId;
19291929

1930-
// Short circuit if we have no loaders to run
1931-
if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
1930+
// Short circuit if we have no loaders to run, unless there's a custom dataStrategy
1931+
// since they may have different revalidation rules (i.e., single fetch)
1932+
if (
1933+
!init.dataStrategy &&
1934+
matchesToLoad.length === 0 &&
1935+
revalidatingFetchers.length === 0
1936+
) {
19321937
let updatedFetchers = markFetchRedirectsDone();
19331938
completeNavigation(
19341939
location,
@@ -3783,7 +3788,7 @@ export function createStaticHandler(
37833788
);
37843789

37853790
// Short circuit if we have no loaders to run (query())
3786-
if (matchesToLoad.length === 0) {
3791+
if (!dataStrategy && matchesToLoad.length === 0) {
37873792
return {
37883793
matches,
37893794
// Add a null for all matched routes for proper revalidation on the client

0 commit comments

Comments
 (0)