fix: resolve all eslint errors (set-state-in-effect, nested components, no-explicit-any)

- Wrap synchronous setState calls in useEffect with startTransition to avoid cascading renders
- Convert nested SortIcon components to renderSortIcon helper functions
- Replace all `any` types with proper interfaces (OverviewData, TrendPoint, RankItem)
- Remove unused formatTokens import in logs page
- Add no-any rule to CLAUDE.md
This commit is contained in:
2026-04-07 15:19:10 +08:00
parent 8b91aa3e97
commit 20a3d399d9
7 changed files with 62 additions and 35 deletions

View File

@@ -1,6 +1,6 @@
"use client";
import { useEffect, useState, useCallback } from "react";
import { useEffect, useState, useCallback, startTransition } from "react";
import Link from "next/link";
import { motion } from "motion/react";
import { Trophy, Users, Cpu, Radio, ArrowUpDown, ArrowDown, ArrowUp } from "lucide-react";
@@ -33,11 +33,11 @@ export default function RankingsPage() {
};
const fetchData = useCallback(async () => {
setLoading(true);
startTransition(() => setLoading(true));
const { start, end } = getEffectiveRange();
const res = await fetch(buildQuery("/api/rankings", { start, end, type: tab, limit: 100 }));
setData(await res.json());
setLoading(false);
const json = await res.json();
startTransition(() => { setData(json); setLoading(false); });
}, [tab, getEffectiveRange]);
useEffect(() => { fetchData(); }, [fetchData]);
@@ -58,12 +58,12 @@ export default function RankingsPage() {
return sortAsc ? diff : -diff;
});
function SortIcon({ col }: { col: SortKey }) {
const renderSortIcon = (col: SortKey) => {
if (sortKey !== col) return <ArrowUpDown className="h-3 w-3" style={{ color: "var(--text-muted)", opacity: 0.4 }} />;
return sortAsc
? <ArrowUp className="h-3 w-3" style={{ color: "var(--accent)" }} />
: <ArrowDown className="h-3 w-3" style={{ color: "var(--accent)" }} />;
}
};
const columns: { key: SortKey | null; label: string; align: "left" | "right" }[] = [
{ key: null, label: t("th.rank"), align: "left" },
@@ -116,7 +116,7 @@ export default function RankingsPage() {
>
{col.key ? (
<span className={`inline-flex items-center gap-1 ${col.align === "right" ? "justify-end" : ""}`}>
{col.label} <SortIcon col={col.key} />
{col.label} {renderSortIcon(col.key)}
</span>
) : col.label}
</th>