annotate react_games/src/API_works/pagination.tsx @ 71:75de5903355c

Giagantic changes that update Dowa library to be more align with stb style array and hashmap. Updated Seobeo to be caching on server side instead of file level caching. Deleted bunch of things I don't really use.
author June Park <parkjune1995@gmail.com>
date Sun, 28 Dec 2025 20:34:22 -0800
parents fb9bcd3145cb
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
37
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
1 import { CSSProperties, startTransition, useCallback, useEffect, useReducer, useRef } from "react";
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
2 import ReactDOM from "react-dom/client";
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
3
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
4 const API_URL = "https://swapi.py4e.com/api/people/";
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
5
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
6 /* ---------- Types ---------- */
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
7 interface PeopleJSON { name: string; birth_year: string; }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
8 interface APIResponse { next: string | null; previous: string | null; results: PeopleJSON[]; }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
9 interface PageData extends APIResponse { isLoading: boolean; curr: string; }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
10
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
11 type Dir = "next" | "prev";
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
12 type Mode = "none" | "page" | "offset" | "cursor" | "link";
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
13 type UrlParams =
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
14 | { mode: "none" }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
15 | { mode: "page"; page: number; limit?: number }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
16 | { mode: "offset"; offset: number; limit?: number }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
17 | { mode: "cursor"; cursor: string; limit?: number; dir?: Dir }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
18 | { mode: "link"; curr: string; next?: string; prev?: string };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
19
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
20 /* ---------- URL <-> Args ---------- */
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
21 function parseArgsFromSearch(): UrlParams {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
22 const sp = new URLSearchParams(location.search);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
23 const mode = (sp.get("mode") as Mode) || "none";
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
24 switch (mode) {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
25 case "none": return { mode };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
26 case "page": return { mode, page: Number(sp.get("page") || 1), limit: sp.get("limit") ? Number(sp.get("limit")) : undefined };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
27 case "offset": return { mode, offset: Number(sp.get("offset") || 0), limit: sp.get("limit") ? Number(sp.get("limit")) : undefined };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
28 case "cursor": return { mode, cursor: sp.get("cursor") || "", limit: sp.get("limit") ? Number(sp.get("limit")) : undefined, dir: (sp.get("dir") as Dir) || undefined };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
29 case "link": return { mode, curr: sp.get("curr") || API_URL, next: sp.get("next") || undefined, prev: sp.get("prev") || undefined };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
30 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
31 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
32
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
33 function uiUrl(basePath: string, args: UrlParams): string {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
34 const sp = new URLSearchParams();
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
35 switch (args.mode) {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
36 case "none":
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
37 return basePath;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
38 case "page":
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
39 sp.set("mode", "page");
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
40 sp.set("page", String(args.page));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
41 if (args.limit != null) sp.set("limit", String(args.limit));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
42 break;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
43 case "offset":
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
44 sp.set("mode", "offset");
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
45 sp.set("offset", String(args.offset));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
46 if (args.limit != null) sp.set("limit", String(args.limit));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
47 break;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
48 case "cursor":
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
49 sp.set("mode", "cursor");
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
50 sp.set("cursor", args.cursor);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
51 if (args.limit != null) sp.set("limit", String(args.limit));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
52 if (args.dir) sp.set("dir", args.dir);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
53 break;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
54 case "link":
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
55 sp.set("mode", "link");
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
56 sp.set("curr", args.curr);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
57 if (args.next) sp.set("next", args.next);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
58 if (args.prev) sp.set("prev", args.prev);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
59 break;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
60 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
61 const q = sp.toString();
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
62 return q ? `${basePath}?${q}` : basePath;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
63 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
64
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
65 /** For this API, upstream URL comes from args. */
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
66 function toUpstreamUrl(args: UrlParams): string {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
67 switch (args.mode) {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
68 case "none": return API_URL;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
69 case "link": return args.curr || API_URL;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
70 case "page": return `${API_URL}?page=${args.page}${args.limit != null ? `&limit=${args.limit}` : ""}`;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
71 case "offset": return `${API_URL}?offset=${args.offset}${args.limit != null ? `&limit=${args.limit}` : ""}`;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
72 case "cursor": return `${API_URL}?cursor=${args.cursor}${args.limit != null ? `&limit=${args.limit}` : ""}${args.dir ? `&dir=${args.dir}` : ""}`;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
73 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
74 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
75
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
76 function argsFromResponse(currUrl: string, resp: APIResponse): UrlParams {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
77 // Prefer LINK mode when API provides next/previous URLs
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
78 return { mode: "link", curr: currUrl, next: resp.next ?? undefined, prev: resp.previous ?? undefined };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
79 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
80
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
81 /* ---------- In-flight dedupe (not a cache) ---------- */
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
82 const inflight = new Map<string, Promise<PageData>>();
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
83
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
84 async function fetchPage(url: string, signal?: AbortSignal): Promise<PageData> {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
85 if (inflight.has(url)) return inflight.get(url)!;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
86
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
87 const p = (async () => {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
88 const res = await fetch(url, { signal });
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
89 console.log(res.headers.get("content-type"));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
90 if (!res.ok) throw new Error(`HTTP ${res.status}`);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
91 const json: APIResponse = await res.json();
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
92 return { ...json, isLoading: false, curr: url } as PageData;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
93 })().finally(() => inflight.delete(url));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
94
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
95 inflight.set(url, p);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
96 return p;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
97 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
98
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
99 /* ---------- Derive next/prev target args (mode-agnostic) ---------- */
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
100 function deriveNav(current: UrlParams, pd: PageData) {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
101 let nextArgs: UrlParams | undefined;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
102 let prevArgs: UrlParams | undefined;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
103
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
104 switch (current.mode) {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
105 case "none":
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
106 case "link": {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
107 nextArgs = pd.next ? { mode: "link", curr: pd.next, next: pd.next, prev: pd.prev || undefined } : undefined;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
108 prevArgs = pd.previous ? { mode: "link", curr: pd.previous, prev: pd.previous, next: pd.next || undefined } : undefined;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
109 break;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
110 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
111 case "page": {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
112 const limit = current.limit;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
113 nextArgs = { mode: "page", page: current.page + 1, limit };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
114 prevArgs = current.page > 1 ? { mode: "page", page: current.page - 1, limit } : undefined;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
115 break;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
116 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
117 case "offset": {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
118 const limit = current.limit ?? 10;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
119 nextArgs = { mode: "offset", offset: current.offset + limit, limit };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
120 prevArgs = current.offset - limit >= 0 ? { mode: "offset", offset: current.offset - limit, limit } : undefined;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
121 break;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
122 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
123 case "cursor": {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
124 // needs server-provided cursors; we’d stash them in pd if available
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
125 // For this API we don't have cursors, so fall back to link behavior above.
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
126 break;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
127 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
128 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
129 return { nextArgs, prevArgs };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
130 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
131
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
132 /* ---------- State ---------- */
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
133 enum ActionType { HYDRATE, LOADING, ERROR }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
134 type Action =
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
135 | { type: ActionType.HYDRATE; data: PageData }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
136 | { type: ActionType.LOADING }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
137 | { type: ActionType.ERROR; error: string };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
138
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
139 const INITIAL: PageData = { next: null, previous: null, results: [], isLoading: false, curr: API_URL };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
140
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
141 function reducer(state: PageData, action: Action): PageData {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
142 switch (action.type) {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
143 case ActionType.HYDRATE: return action.data;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
144 case ActionType.LOADING: return { ...state, isLoading: true };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
145 case ActionType.ERROR: return { ...state, isLoading: false };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
146 default: return state;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
147 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
148 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
149
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
150 /* ---------- Styles & Row ---------- */
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
151 const styles: { row: CSSProperties; toolbar: CSSProperties } = {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
152 row: { display: "grid", gridTemplateColumns: "repeat(2, 1fr)" },
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
153 toolbar: { display: "flex", gap: 8, marginBottom: 8 },
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
154 };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
155
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
156 const PersonRow = ({ p }: { p: PeopleJSON }) => (
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
157 <div style={styles.row}>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
158 <p>{p.name}</p>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
159 <p>{p.birth_year}</p>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
160 </div>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
161 );
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
162
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
163 /* ---------- Component ---------- */
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
164 const People = () => {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
165 const [page, dispatch] = useReducer(reducer, INITIAL);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
166 const ctrlRef = useRef<AbortController | null>(null);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
167
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
168 const load = useCallback((args: UrlParams, pushUrl = true) => {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
169 dispatch({ type: ActionType.LOADING });
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
170
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
171 startTransition(async () => {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
172 ctrlRef.current?.abort();
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
173 const ctrl = new AbortController();
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
174 ctrlRef.current = ctrl;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
175
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
176 try {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
177 const upstream = toUpstreamUrl(args);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
178 const data = await fetchPage(upstream, ctrl.signal);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
179
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
180 // Auto-detect LINK and sync UI URL *from the response* (URL is the source of truth)
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
181 const linkArgs = argsFromResponse(upstream, data);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
182 if (pushUrl) history.pushState(null, "", uiUrl(location.pathname, linkArgs));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
183
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
184 dispatch({ type: ActionType.HYDRATE, data });
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
185 } catch (e: any) {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
186 if (e?.name !== "AbortError") dispatch({ type: ActionType.ERROR, error: String(e?.message ?? e) });
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
187 }
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
188 });
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
189 }, []);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
190
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
191 // Initial load + back/forward
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
192 useEffect(() => {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
193 const applyFromLocation = () => load(parseArgsFromSearch(), false);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
194 window.addEventListener("popstate", applyFromLocation);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
195 applyFromLocation();
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
196 return () => window.removeEventListener("popstate", applyFromLocation);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
197 }, [load]);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
198
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
199 // Click handlers: derive target solely from current URL + current page data
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
200 const navigate = useCallback((dir: Dir) => {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
201 const current = parseArgsFromSearch();
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
202 const { nextArgs, prevArgs } = deriveNav(current, page);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
203 const target = dir === "next" ? nextArgs : prevArgs;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
204 if (!target) return;
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
205 // push new URL first so URL remains the source of truth
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
206 history.pushState(null, "", uiUrl(location.pathname, target));
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
207 load(target, false); // do not push again inside load
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
208 }, [page, load]);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
209
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
210 const { nextArgs, prevArgs } = deriveNav(parseArgsFromSearch(), page);
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
211
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
212 return (
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
213 <div>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
214 <div style={styles.toolbar}>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
215 <button disabled={!prevArgs} onClick={() => navigate("prev")}>prev</button>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
216 <button disabled={!nextArgs} onClick={() => navigate("next")}>next</button>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
217 </div>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
218
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
219 {page.isLoading && <p>Loading…</p>}
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
220
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
221 {!page.isLoading && (
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
222 <>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
223 <div style={{ ...styles.row, borderBottom: "1px solid #000" }}>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
224 <strong>Name</strong>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
225 <strong>Birth Year</strong>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
226 </div>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
227 {page.results.map((p) => <PersonRow key={p.name} p={p} />)}
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
228 </>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
229 )}
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
230 </div>
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
231 );
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
232 };
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
233
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
234 export {
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
235 People,
fb9bcd3145cb [ReactGames] Few games I made using react just to practice few things.
MrJuneJune <me@mrjunejune.com>
parents:
diff changeset
236 }