You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NextJS中Supabase Auth水合(Hydration)错误的原因及修复方案

NextJS水合错误(Hydration failed)的原因与修复方案

错误原因

  • 服务器与客户端初始状态不匹配:服务器端无法读取浏览器中的Supabase session(存储在cookie或localStorage),初始session值为null,会渲染Auth登录组件;但客户端可能已有缓存的session,在hydration阶段,useEffect执行前若客户端快速获取到session,会导致客户端渲染结果与服务器端不一致,触发水合错误。
  • session存在时无有效返回内容:当session存在时,组件未返回任何JSX(实际返回undefined),若客户端在hydration过程中session状态从null变为存在,UI会从Auth组件突然变为空,进一步加剧水合不匹配问题。

修复方法

针对上述问题,通过以下代码修改解决:

修改后的完整代码

"use client";

import { useState, useEffect } from "react";
import { supabase } from "@/lib/supabaseClient";
import { Auth } from "@supabase/auth-ui-react";
import { ThemeSupa } from "@supabase/auth-ui-shared";
import { Session } from "@supabase/supabase-js";
import { useRouter } from "next/navigation";

export default function Login() {
  const [session, setSession] = useState<Session | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const router = useRouter();

  useEffect(() => {
    const fetchSession = async () => {
      const { data: { session } } = await supabase.auth.getSession();
      setSession(session);
      setIsLoading(false);
    };

    fetchSession();

    const { data: { subscription } } = supabase.auth.onAuthStateChange((_event, session) => {
      setSession(session);
      if (session) router.push("/");
    });

    return () => subscription.unsubscribe();
  }, [router]);

  if (isLoading) {
    return (
      <div className="min-h-screen flex items-center justify-center">
        <p>加载中...</p>
      </div>
    );
  }

  if (!session) {
    return (
      <div className="min-h-screen flex flex-col items-center justify-center">
        <div className="w-full max-w-md">
          <Auth
            supabaseClient={supabase}
            appearance={{ theme: ThemeSupa }}
            providers={[]}
          />
        </div>
      </div>
    );
  }

  return (
    <div className="min-h-screen flex items-center justify-center">
      <p>已登录,正在跳转...</p>
    </div>
  );
}

关键修改点说明

  1. 添加加载状态isLoading:初始设为true,服务器端和客户端初始渲染都显示加载UI,确保hydration阶段两端内容完全一致,避免状态突变导致的不匹配。
  2. 补充session存在时的返回内容:不再返回undefined,而是显示跳转提示,同时通过useRouter自动跳转到首页,保证UI始终有有效输出。
  3. 优化session获取逻辑:用async/await异步获取session,完成后再切换加载状态,确保客户端在hydration完成后才更新UI;移除不必要的typeof window判断("use client"组件已确保代码只在客户端执行)。

内容的提问来源于stack exchange,提问作者NBRCS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 00:54:58