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

Next.js 14 App Router:登录后AuthButton组件无法自动更新求助

解决Next.js 14 App Router中AuthButton无法实时同步用户状态的问题

问题诊断

当前代码的核心问题:

  • AuthButton仅在组件挂载时通过useEffect获取一次用户状态,后续不会监听Supabase的用户状态变更
  • UserContext未设置持续监听机制,导致登录/登出后全局状态无法自动同步

解决方案步骤

1. 重构UserContext,添加Supabase状态监听

完善@/context/user.tsx的实现,让它自动监听Supabase用户状态变化:

"use client";

import { createContext, useContext, useEffect, useState } from "react";
import { User } from "@supabase/supabase-js";
import { createClient } from "@/utils/supabase/client";

type UserContextType = {
  userContext: User | null;
  setUserContext: React.Dispatch<React.SetStateAction<User | null>>;
};

const UserContext = createContext<UserContextType | undefined>(undefined);

export function UserContextWrapper({ children }: { children: React.ReactNode }) {
  const [userContext, setUserContext] = useState<User | null>(null);
  const supabase = createClient();

  useEffect(() => {
    // 初始化获取当前用户
    const initUser = async () => {
      const { data: { user } } = await supabase.auth.getUser();
      setUserContext(user);
    };
    initUser();

    // 监听用户状态变化(登录/登出/会话更新)
    const authSubscription = supabase.auth.onAuthStateChange((_event, session) => {
      setUserContext(session?.user ?? null);
    });

    // 组件卸载时取消监听
    return () => authSubscription.unsubscribe();
  }, [supabase]);

  return (
    <UserContext.Provider value={{ userContext, setUserContext }}>
      {children}
    </UserContext.Provider>
  );
}

export const useUserContext = () => {
  const context = useContext(UserContext);
  if (!context) {
    throw new Error("useUserContext必须在UserContextWrapper内部使用");
  }
  return context;
};

2. 简化AuthButton组件,移除冗余逻辑

修改AuthButton.tsx,直接使用Context中的全局用户状态,无需重复获取:

"use client";

import { signOut } from "@/utils/supabase/supabaseAuth";
import Link from "next/link";
import { useUserContext } from '@/context/user';

export default function AuthButton() {
  const { userContext } = useUserContext();

  return userContext ? (
    <div className="flex items-center gap-4">
      {userContext.email}
      <form action={signOut}>
        <button className="py-2 px-4 rounded-md no-underline bg-btn-background hover:bg-btn-background-hover">
          Logout
        </button>
      </form>
    </div>
  ) : (
    <Link
      href="/login"
      className="py-2 px-3 flex rounded-md no-underline bg-btn-background hover:bg-btn-background-hover"
    >
      Login
    </Link>
  );
}

3. 确保登录/登出操作的状态同步

检查supabaseAuth.ts中的登录登出函数,确保操作完成后触发状态更新:

// signIn 示例(服务端操作)
import { createClient } from "@/utils/supabase/server";
import { redirect } from "next/navigation";

export async function signIn(formData: FormData) {
  const supabase = createClient();
  const email = formData.get("email") as string;
  const password = formData.get("password") as string;

  const { error } = await supabase.auth.signInWithPassword({ email, password });

  if (error) {
    redirect("/login?message=Invalid credentials");
  }

  // 登录成功后重定向,客户端监听会自动捕获状态变化
  redirect("/");
}

// signOut 示例(服务端操作)
export async function signOut() {
  const supabase = createClient();
  await supabase.auth.signOut();
  redirect("/");
}

关键原理说明

  • 通过Supabase的onAuthStateChange监听用户状态的所有变更(登录、登出、会话过期等),实时更新全局Context
  • 依赖用户状态的组件(如AuthButton)会自动响应Context的状态变化并重新渲染
  • 移除AuthButton中冗余的用户获取逻辑,避免重复请求和状态不同步

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:54:51