加载状态和验证状态未在导航栏组件上正确显示

问题描述 投票:0回答:1

在我的 NextJS15 项目中,我的导航栏有一个 sign in / sign out 组件。我正在使用 Supabase auth(使用密码和电子邮件登录)。

我的登录/退出按钮的行为有问题。

预期的行为是

  • 注销后,如果刷新页面,您只会看到 sign in 按钮。
  • 登录或注销时,您应该会看到来自 lucide-react 的 Loader2,然后是 sign out 按钮。

我当前的代码给了我什么

  • 注销后,如果刷新页面,我会看到 sign in 按钮(一切都很好!)。
  • 在登录过程中,当 supabase auth 执行其操作时,我没有看到 Loader2 旋转(不好!)。
  • 登录后,登录按钮尚未切换为退出。我必须刷新页面才能看到退出(不好!)。
  • 如果刷新页面,会在 登录 / 退出之间快速切换,而不是 Loader2 旋转(不好!)。

代码看起来像这样

export default function AuthButton() {
  const router = useRouter();
  const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const supabase = createClient();

  useEffect(() => {
    const { data } = supabase.auth.onAuthStateChange((event, session) => {
      if (event === "SIGNED_IN" || event === "INITIAL_SESSION") {
        setIsAuthenticated(!!session);
      } else if (event === "SIGNED_OUT") {
        setIsAuthenticated(false);
        router.push("/login");
      }
      setIsLoading(false);
    });

    return () => {
      data.subscription.unsubscribe();
    };
  }, [router, supabase.auth]);

  const handleSignOut = async () => {
    try {
      await supabase.auth.signOut();
    } catch (error) {
      console.error("Error signing out:", error);
    }
  };

  if (isAuthenticated) {
    return (
      <>
        {isLoading ? (
          <div className="pl-5 pt-3">
            <Loader2 className="mr-2 h-4 w-4 animate-spin" />
          </div>
        ) : (
          <Button variant="ghost" onClick={handleSignOut} aria-label="Sign out">
            Sign Out
          </Button>
        )}
      </>
    );
  }

  return (
    <Button asChild variant="ghost" aria-label="Sign in">
      <Link href="/login">Sign In</Link>
    </Button>
  );
}

预先感谢您的帮助。

authentication next.js frontend navbar supabase
1个回答
0
投票

我建议不要让您的 AuthButton 处理您拥有的身份验证状态。

您如何处理服务器端的事情?

说实话,我会完全重写你的AuthButton。我会安装中间件来处理用户状态,然后只有一个 AuthButton 组件来检查是否有用户。

完成中间件设置后,这将是您的新 AuthButton 组件:

export async function AuthButton() {
  const supabase = await supabaseServer();
  const {
    data: { user },
  } = await supabase.auth.getUser();

  return (
    <Link
      className="btn btn-primary"
      href={user ? "/auth/signout" : "/auth/signin"}
    >
      {user ? "Sign Out" : "Sign in"}
    </Link>
  );
}

/auth/signout 是一个路由处理程序,它将注销用户并在注销后重定向到您想要的任何页面。

supabaseServer() 来自 SSR 包,该包是从此处找到的 Supabase 指南引用的:https://supabase.com/docs/guides/auth/server-side/nextjs

此外,我还为任何想要使用命令

npx next-mods
在大约一分钟内将 Supabase 身份验证正确添加到其 Next.js 项目的人开发了一个 CLI 工具。如果你想尝试一下,我很乐意提供反馈。希望这有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.