Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -428,3 +428,4 @@
- zeromask1337
- zheng-chuang
- zxTomw
- ZxBing0066
80 changes: 80 additions & 0 deletions integration/single-fetch-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3429,6 +3429,86 @@ test.describe("single-fetch", () => {
await page.waitForSelector("#other");
expect(msgs).toEqual([]);
});

test("Aborted loaders don't cause corresponding result not found errors", async ({ page }) => {
let fixture = await createFixture({
files: {
...files,
"app/routes/_index.tsx": js`
import { useEffect } from "react";
import { Form, redirect, useFetcher, NavLink } from "react-router";

export default function Index() {
return (
<>
<NavLink id="linkA" to="/a" end>
Link
</NavLink>
</>
);
}
`,
"app/routes/a.tsx": js`
import { useEffect } from "react";
import { useFetcher, NavLink, Outlet } from "react-router";

export default function Comp() {
const loaderFetcher = useFetcher();
const actionFetcher = useFetcher();

useEffect(() => {
if (loaderFetcher.state === 'idle' && !loaderFetcher.data) {
loaderFetcher.load('/loader');
}
}, [loaderFetcher]);

return (
<>
<p id="a">A</p>
<button id="action" onClick={() => actionFetcher.submit(null, { method: "post", action: "/action" })}>
Action
</button>
<NavLink id="linkB" to="/a/b" end>
Link
</NavLink>
<Outlet/>
</>
);
}
`,
"app/routes/a.b.tsx": js`
export default function Comp() {
return <p id="b">B</p>;
}
`,
"app/routes/loader.tsx": js`
export async function loader() {
await new Promise((r) => setTimeout(r, 500));
return 'nope';
}
`,
"app/routes/action.tsx": js`
export async function action() {
await new Promise((r) => setTimeout(r, 500));
return 'nope';
}
`,
},
});
let appFixture = await createAppFixture(fixture);
let app = new PlaywrightFixture(appFixture, page);

// Capture console logs and uncaught errors
let msgs: string[] = [];
page.on("console", (msg) => msgs.push(msg.text()));
page.on("pageerror", (error) => msgs.push(error.message));

await app.goto("/a", true);
await page.locator("#action").click();
await page.locator("#linkB").click();
await page.waitForSelector("#b");
expect(msgs).toEqual([]);
});
});

test.describe("prefetching", () => {
Expand Down
8 changes: 8 additions & 0 deletions packages/react-router/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2901,6 +2901,14 @@ export function createRouter(init: RouterInit): Router {
}

if (request.signal.aborted) {
matches
.filter((m) => m.shouldLoad)
.forEach((m) => {
dataResults[m.route.id] = {
type: ResultType.error,
error: new Error("Data loading aborted"),
};
});
return dataResults;
}

Expand Down
Loading