Files
jiang13-forum/frontend/src/hooks/useAuth.tsx
freefire 44eed97fe0 feat: 首页 Go SSR 与 React hydrate 同构,消壳层与帖行闪动
补齐侧栏/右栏图标与徽章、鉴权种子、StaticFeedList,并修正嵌套 a 与标题徽章对齐。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-01 07:07:38 +08:00

71 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createContext, useContext, useEffect, useState, useCallback, useRef, ReactNode } from 'react';
import { api } from '../api/client';
import type { User } from '../api/types';
import { clearAllFeedCache } from '../utils/feedCache';
import { clearSessionSnapshots } from '../utils/sessionPageCache';
import { peekAuthSeed } from '../utils/authBoot';
interface AuthCtx {
user: User | null;
loading: boolean;
refresh: () => Promise<void>;
logout: () => Promise<void>;
}
const AuthContext = createContext<AuthCtx>({
user: null, loading: true,
refresh: async () => {}, logout: async () => {},
});
export function AuthProvider({ children }: { children: ReactNode }) {
// peek 不清种子StrictMode 重挂 / initializer 双调仍与 SSR 同构
const [user, setUser] = useState<User | null>(() => {
const s = peekAuthSeed();
return s.hasSeed ? s.user : null;
});
const [loading, setLoading] = useState(() => !peekAuthSeed().hasSeed);
const refresh = useCallback(async () => {
try {
const data = await api.me();
setUser(data.user ?? null);
} catch {
setUser(null);
} finally {
setLoading(false);
}
}, []);
// 有 SSR 种子时仍后台校验;无种子则首屏拉取
// 不清空 auth 种子StrictMode 重挂会再次跑 useState initializer破坏性 clear 会导致 user 空窗闪动
useEffect(() => { void refresh(); }, [refresh]);
const prevUserId = useRef<number | null | 'init'>('init');
useEffect(() => {
if (loading) return;
const id = user?.id ?? null;
if (prevUserId.current === 'init') {
prevUserId.current = id;
return;
}
if (prevUserId.current !== id) {
prevUserId.current = id;
clearSessionSnapshots();
clearAllFeedCache();
}
}, [user, loading]);
const logout = async () => {
await api.logout();
setUser(null);
};
return (
<AuthContext.Provider value={{ user, loading, refresh, logout }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);