feat: migrate GitHub stars fetch to TanStack Query

Replace the manual useEffect + fetch in NavbarGitHubStars with
useQuery from @tanstack/react-query. This gives the component
caching, request deduplication, automatic retries, and devtools
visibility for free.

The useLatestRelease hook referenced in the issue has already been
removed from hero-section.tsx, so only the stars badge needed
migration.

Closes #1198
This commit is contained in:
Matt Van Horn 2026-04-10 03:08:06 -07:00
parent 5da2d95d80
commit 9cfaa72325
2 changed files with 21 additions and 22 deletions

View file

@ -1,9 +1,11 @@
"use client";
import { IconBrandGithub } from "@tabler/icons-react";
import { useQuery } from "@tanstack/react-query";
import { motion, useMotionValue, useSpring } from "motion/react";
import * as React from "react";
import { cn } from "@/lib/utils";
import { cacheKeys } from "@/lib/query-client/cache-keys";
// ---------------------------------------------------------------------------
// Per-digit scrolling wheel
@ -243,28 +245,21 @@ function NavbarGitHubStars({
href = "https://github.com/MODSetter/SurfSense",
className,
}: NavbarGitHubStarsProps) {
const [stars, setStars] = React.useState(0);
const [isLoading, setIsLoading] = React.useState(true);
React.useEffect(() => {
const abortController = new AbortController();
fetch(`https://api.github.com/repos/${username}/${repo}`, {
signal: abortController.signal,
})
.then((res) => res.json())
.then((data) => {
if (data && typeof data.stargazers_count === "number") {
setStars(data.stargazers_count);
}
})
.catch((err) => {
if (err instanceof Error && err.name !== "AbortError") {
console.error("Error fetching stars:", err);
}
})
.finally(() => setIsLoading(false));
return () => abortController.abort();
}, [username, repo]);
const { data: stars = 0, isLoading } = useQuery({
queryKey: cacheKeys.github.repoStars(username, repo),
queryFn: async ({ signal }) => {
const res = await fetch(
`https://api.github.com/repos/${username}/${repo}`,
{ signal },
);
const data = await res.json();
if (data && typeof data.stargazers_count === "number") {
return data.stargazers_count as number;
}
return 0;
},
staleTime: 5 * 60 * 1000,
});
return (
<a

View file

@ -91,6 +91,10 @@ export const cacheKeys = {
publicChat: {
byToken: (shareToken: string) => ["public-chat", shareToken] as const,
},
github: {
repoStars: (username: string, repo: string) =>
["github", "repo-stars", username, repo] as const,
},
publicChatSnapshots: {
all: ["public-chat-snapshots"] as const,
bySearchSpace: (searchSpaceId: number) =>