diff --git a/web/usercenter/components/UserCenter.tsx b/web/usercenter/components/UserCenter.tsx index 86c7bf7..7d8ba5f 100644 --- a/web/usercenter/components/UserCenter.tsx +++ b/web/usercenter/components/UserCenter.tsx @@ -45,16 +45,11 @@ export default function UserCenter() { const [authed, setAuthed] = useState(false); const [ready, setReady] = useState(false); - const [mounted, setMounted] = useState(false); const [me, setMe] = useState(null); const [view, setView] = useState('overview'); const [dir, setDir] = useState(0); const touchRef = useRef({ x: 0, y: 0 }); - // SSR/首帧标记:服务端与客户端首次渲染都读不到 localStorage,必须渲染同一份中性 - // 首帧(避免水合不一致)。mount 后再据 hasRefresh() 乐观渲染外壳。 - useEffect(() => setMounted(true), []); - const loadMe = useCallback(() => { api.getMe().then(setMe).catch(() => {}); }, [api]); @@ -207,12 +202,12 @@ export default function UserCenter() { const spinner =
{t('loading')}
; - // ① SSR + 首次客户端渲染:读不到 localStorage,渲染中性首帧(与服务端 HTML 一致,防 - // 水合不一致)。② mount 后引导仍在进行(!ready):有 refresh token → 乐观渲染完整外壳 - // (只在内容区转圈),没 token → 直接登录页(均无闪现)。③ 引导完成:未登录→登录页、 - // 已登录→外壳 + 真实视图。外壳在 ②③ 始终在位 → 刷新不再整页重绘。 - if (!mounted) return spinner; - if (!ready) return hasRefresh() ? appShell(spinner) : ; + // 引导(会话续期)期间一律渲染**应用外壳骨架**(顶栏/导航 + 内容区加载态)。关键: + // · SSR 与客户端首帧渲染同一份外壳(不在 render 期读 localStorage/hasRefresh)→ 无水合 + // 不一致,首帧(静态 HTML)即外壳。 + // · 引导完成后:已登录→外壳 + 真实视图(**只换内容区**,顶栏/导航原地不动),未登录→登录页。 + // 于是刷新时不再"裸屏 spinner → 外壳 → 内容"多段重绘,只有内容区一次替换。 + if (!ready) return appShell(spinner); if (!authed) return ; return appShell(main); }