perf(platform): 创作页加载 - 合并用户数据与余额请求并按路由延迟加载
This commit is contained in:
@@ -1,76 +1,44 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useEffect } from "react";
|
||||
|
||||
import { getWallet } from "@/services/api/wallet";
|
||||
|
||||
const WALLET_REFRESH_INTERVAL_MS = 30_000;
|
||||
|
||||
type WalletBalanceSnapshot = {
|
||||
userId: string;
|
||||
availableMicrocredits: number | null;
|
||||
refreshing: boolean;
|
||||
};
|
||||
const walletBalanceQueryKey = (userId: string) => ["wallet-balance", userId] as const;
|
||||
|
||||
export function useWalletBalance(userId?: string, enabled = true) {
|
||||
const activeUserId = enabled ? userId || "" : "";
|
||||
const requestSequence = useRef(0);
|
||||
const [snapshot, setSnapshot] = useState<WalletBalanceSnapshot>({ userId: "", availableMicrocredits: null, refreshing: false });
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
const requestedUserId = activeUserId;
|
||||
const sequence = ++requestSequence.current;
|
||||
if (!requestedUserId) {
|
||||
setSnapshot({ userId: "", availableMicrocredits: null, refreshing: false });
|
||||
return;
|
||||
}
|
||||
setSnapshot((current) => ({
|
||||
userId: requestedUserId,
|
||||
availableMicrocredits: current.userId === requestedUserId ? current.availableMicrocredits : null,
|
||||
refreshing: true,
|
||||
}));
|
||||
try {
|
||||
const queryClient = useQueryClient();
|
||||
const queryKey = walletBalanceQueryKey(activeUserId);
|
||||
const query = useQuery({
|
||||
queryKey,
|
||||
enabled: Boolean(activeUserId),
|
||||
queryFn: async () => {
|
||||
const wallet = await getWallet(1, 1);
|
||||
if (sequence !== requestSequence.current) return;
|
||||
if (wallet.account.userId !== requestedUserId) throw new Error("积分账户与当前用户不一致");
|
||||
setSnapshot({ userId: requestedUserId, availableMicrocredits: wallet.account.availableMicrocredits, refreshing: false });
|
||||
} catch (error) {
|
||||
if (sequence !== requestSequence.current) return;
|
||||
console.warn("积分余额刷新失败", error);
|
||||
setSnapshot((current) => ({
|
||||
userId: requestedUserId,
|
||||
availableMicrocredits: current.userId === requestedUserId ? current.availableMicrocredits : null,
|
||||
refreshing: false,
|
||||
}));
|
||||
}
|
||||
}, [activeUserId]);
|
||||
if (wallet.account.userId !== activeUserId) throw new Error("积分账户与当前用户不一致");
|
||||
return wallet.account.availableMicrocredits;
|
||||
},
|
||||
staleTime: 15_000,
|
||||
refetchInterval: WALLET_REFRESH_INTERVAL_MS,
|
||||
refetchOnWindowFocus: true,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!activeUserId) {
|
||||
requestSequence.current += 1;
|
||||
setSnapshot({ userId: "", availableMicrocredits: null, refreshing: false });
|
||||
return;
|
||||
}
|
||||
void refresh();
|
||||
const timer = window.setInterval(() => void refresh(), WALLET_REFRESH_INTERVAL_MS);
|
||||
const handleFocus = () => void refresh();
|
||||
const handleVisibility = () => {
|
||||
if (document.visibilityState === "visible") void refresh();
|
||||
};
|
||||
window.addEventListener("focus", handleFocus);
|
||||
window.addEventListener("wallet:updated", handleFocus);
|
||||
document.addEventListener("visibilitychange", handleVisibility);
|
||||
if (!activeUserId) return;
|
||||
const handleUpdated = () => void queryClient.invalidateQueries({ queryKey: walletBalanceQueryKey(activeUserId) });
|
||||
window.addEventListener("wallet:updated", handleUpdated);
|
||||
return () => {
|
||||
requestSequence.current += 1;
|
||||
window.clearInterval(timer);
|
||||
window.removeEventListener("focus", handleFocus);
|
||||
window.removeEventListener("wallet:updated", handleFocus);
|
||||
document.removeEventListener("visibilitychange", handleVisibility);
|
||||
window.removeEventListener("wallet:updated", handleUpdated);
|
||||
};
|
||||
}, [activeUserId, refresh]);
|
||||
}, [activeUserId, queryClient]);
|
||||
|
||||
useEffect(() => {
|
||||
if (query.error) console.warn("积分余额刷新失败", query.error);
|
||||
}, [query.error]);
|
||||
|
||||
const snapshotMatchesUser = snapshot.userId === activeUserId;
|
||||
return {
|
||||
availableMicrocredits: snapshotMatchesUser ? snapshot.availableMicrocredits : null,
|
||||
refreshing: snapshotMatchesUser ? snapshot.refreshing : Boolean(activeUserId),
|
||||
refresh,
|
||||
availableMicrocredits: query.data ?? null,
|
||||
refreshing: query.isFetching,
|
||||
refresh: query.refetch,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user