utility
useGitHubStars
Fetches the star count of a public GitHub repository. Includes an in-memory cache with a 1-hour TTL to respect the API rate limit, and automatically cancels the request if the repo changes.
useGitHubStars.ts
import { useState, useEffect } from "react"
interface GitHubStarsState {
stars: number | null
loading: boolean
error: string | null
}
const cache = new Map<string, { value: number; ts: number }>()
const TTL_MS = 60 * 60 * 1000 // 1 hour
export function useGitHubStars(repo: string): GitHubStarsState {
const [state, setState] = useState<GitHubStarsState>({
stars: null,
loading: true,
error: null,
})
useEffect(() => {
const cached = cache.get(repo)
if (cached && Date.now() - cached.ts < TTL_MS) {
setState({ stars: cached.value, loading: false, error: null })
return
}
let cancelled = false
setState({ stars: null, loading: true, error: null })
fetch(`https://api.github.com/repos/${repo}`)
.then((res) => {
if (!res.ok) throw new Error(`HTTP ${res.status}`)
return res.json()
})
.then((data) => {
if (!cancelled && typeof data.stargazers_count === "number") {
cache.set(repo, { value: data.stargazers_count, ts: Date.now() })
setState({ stars: data.stargazers_count, loading: false, error: null })
}
})
.catch((err) => {
if (!cancelled) setState({ stars: null, loading: false, error: err.message })
})
return () => { cancelled = true }
}, [repo])
return state
}Was this helpful?
Sign in to give feedback
