Skip to content

Commit 47f8948

Browse files
committed
feat(contributors): type Contributor, DRY token, unmount-safe state updates
1 parent 58bbb99 commit 47f8948

File tree

1 file changed

+32
-20
lines changed

1 file changed

+32
-20
lines changed

src/pages/Contributors/Contributors.tsx

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
import { ghFetch as gh } from "../../lib/githubFetch";
22
import { useEffect, useState } from "react";
33

4+
type Contributor = {
5+
id: number;
6+
login: string;
7+
avatar_url: string;
8+
html_url: string;
9+
contributions: number;
10+
};
11+
412
export default function Contributors() {
5-
const [contributors, setContributors] = useState<any[]>([]);
13+
const [contributors, setContributors] = useState<Contributor[]>([]);
614
const [error, setError] = useState<string>("");
715
const [loading, setLoading] = useState<boolean>(true);
816

917
useEffect(() => {
10-
async function getToken() {
11-
return (
12-
localStorage.getItem("gh_pat") ||
13-
localStorage.getItem("github_pat") ||
14-
localStorage.getItem("token") ||
15-
""
16-
);
17-
}
18+
const ac = new AbortController();
19+
let isMounted = true;
20+
21+
const getToken = () =>
22+
localStorage.getItem("gh_pat") ||
23+
localStorage.getItem("github_pat") ||
24+
localStorage.getItem("token") ||
25+
"";
1826

1927
async function resolveRepoFullName(token: string): Promise<string | null> {
2028
// Try to find the repo by searching both org and user scopes and dash/underscore variants
@@ -53,11 +61,7 @@ export default function Contributors() {
5361
setLoading(true);
5462
setError("");
5563
setContributors([]);
56-
const token =
57-
localStorage.getItem("gh_pat") ||
58-
localStorage.getItem("github_pat") ||
59-
localStorage.getItem("token") ||
60-
"";
64+
const token = getToken();
6165

6266
try {
6367
const fallback = "ASR1015/github_tracker";
@@ -72,6 +76,7 @@ export default function Contributors() {
7276
// Some repos return 204 No Content when there are no contributors.
7377
// res.ok is true for 204, but res.json() would throw; handle it explicitly.
7478
if (res.status === 204) {
79+
if (!isMounted) return;
7580
setContributors([]);
7681
return;
7782
}
@@ -82,19 +87,26 @@ export default function Contributors() {
8287
}
8388

8489
const data = await res.json();
85-
setContributors(Array.isArray(data) ? data : []);
90+
if (!isMounted) return;
91+
setContributors(Array.isArray(data) ? (data as Contributor[]) : []);
8692
} catch (err: any) {
87-
setError(
88-
err?.message ||
89-
"Failed to fetch contributors. Check owner/repo and token (use 'repo' scope if private)."
90-
);
93+
if (isMounted)
94+
setError(
95+
err?.message ||
96+
"Failed to fetch contributors. Check owner/repo and token (use 'repo' scope if private)."
97+
);
9198
console.error("[contributors] error", err);
9299
} finally {
93-
setLoading(false);
100+
if (isMounted) setLoading(false);
94101
}
95102
}
96103

97104
loadContributors();
105+
106+
return () => {
107+
isMounted = false;
108+
ac.abort();
109+
};
98110
}, []);
99111

100112
return (

0 commit comments

Comments
 (0)