react-query's fetchNextPage cancels a next page still loading and sends it again by default.
Our requests ignore the abort signal, so the server ran both: the feed's read-ahead effect
re-runs on scroll frames before isFetchingNextPage reaches it, and on prod every feed page
went out 2-3 times (a 0.8 s title sort queued to 2.3 s). Every call now passes NEXT_PAGE
({cancelRefetch: false}), lint-enforced, with a contract test.
32 lines
1.1 KiB
TypeScript
32 lines
1.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { eslint } from "./lintProbe.testkit";
|
|
|
|
// eslint.config.js: a bare `fetchNextPage()` cancels the page already loading and sends it again
|
|
// (E31 S4e). Pins that the rule keeping every call on NEXT_PAGE actually fires.
|
|
const MESSAGE = "fetchNextPage() cancels";
|
|
|
|
async function hits(source: string): Promise<number> {
|
|
const [result] = await eslint.lintText(source, { filePath: "src/components/__probe.tsx" });
|
|
return (result?.messages ?? []).filter((m) => m.message.startsWith(MESSAGE)).length;
|
|
}
|
|
|
|
describe("a next-page fetch", () => {
|
|
it("is refused bare, on the query or destructured", async () => {
|
|
expect(
|
|
await hits("export const a = (q: { fetchNextPage(): void }) => q.fetchNextPage();\n"),
|
|
).toBe(1);
|
|
expect(await hits("export const b = (fetchNextPage: () => void) => fetchNextPage();\n")).toBe(
|
|
1,
|
|
);
|
|
});
|
|
|
|
it("passes with NEXT_PAGE", async () => {
|
|
expect(
|
|
await hits(
|
|
'import { NEXT_PAGE } from "../lib/nextPage";\nexport const c = (q: { fetchNextPage(o: unknown): void }) => q.fetchNextPage(NEXT_PAGE);\n',
|
|
),
|
|
).toBe(0);
|
|
});
|
|
});
|