Files
jiang13-forum/frontend/src/hooks/useAuth.tsx
freefire 3c6d8cb891 feat(ssr): 帖子页全量 SSR——作者卡/目录首帧服务端渲染,消除冗余首屏请求
- 帖子快照携带作者主页资料与统计(authorProfile/authorStats),
  SSR 端与客户端预热均取 /api/users/:id;PostAuthorCard 首帧直接渲染,
  不再挂载后请求,统计数字不再显示 — 占位
- MainLayout 首帧从已 seed 的帖子快照派生右栏 outline(作者卡+文章目录),
  修复 outline 仅靠 effect 上报导致 SSR 不渲染右栏的问题
- 壳层首屏请求门控:useAuth 有种子跳过 /api/me、branding 缓存命中不重拉、
  侧栏三个区块首屏用 seed 缓存、未读数首屏跳过即时请求(轮询/事件刷新保留)
- serverDom(linkedom) 修复:DOMParser 片段包裹、属性顺序、SVG 自闭合展开
- 验证:首页与帖子页 hydration 后仅剩 pageview 上报,0 hydration 错误
2026-09-10 05:04:31 +08:00

75 lines
2.2 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 +data / 冷启动预热已注入登录态种子(含已确认访客 null)时首屏不重复请求;
// 无种子(纯 SPA 且未预热)才首屏拉取。登录/退出均显式更新状态,不依赖 mount 校验。
// 不清空 auth 种子:StrictMode 重挂会再次跑 useState initializer,破坏性 clear 会导致 user 空窗闪动
useEffect(() => {
if (peekAuthSeed().hasSeed) return;
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);