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

Supabase+Next.js+Toast集成:解决登录组件的端组件冲突方案

解决Next.js中Supabase登录组件的服务端/客户端兼容问题

核心问题拆解

你的组件同时混用了服务端组件特性(async/await、服务端初始化Supabase)和客户端组件特性(useState、toast、表单交互),这在Next.js的组件模型中是不允许的,必须明确组件的运行环境并调整代码逻辑。

正确实现方案

1. 标记组件为客户端组件

在组件文件最顶部添加'use client'指令,强制组件在客户端运行,这样才能使用React Hooks、Toast这类仅客户端可用的API。

2. 调整Supabase与用户信息获取逻辑

服务端没有浏览器的Auth Cookie,无法获取当前登录用户,因此需要将用户信息获取逻辑移到客户端的useEffect中执行。

3. 修复表单提交逻辑

改用客户端表单提交方式,避免服务端formAction与客户端交互逻辑的冲突。

修改后的完整代码

'use client'; // 必须放在文件最顶部

import { useState, useEffect } from 'react';
import { createClient } from '@supabase/supabase-js';
import { toast } from 'your-toast-library'; // 替换为你实际使用的Toast库
import Input from './Input'; // 替换为你的Input组件路径
import Button from './Button'; // 替换为你的Button组件路径
import Link from 'next/link';

export default function Login() {
  const supabase = createClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
  );
  
  const [isLoading, setIsLoading] = useState(false);
  const [user, setUser] = useState(null);

  // 组件挂载后在客户端获取当前用户
  useEffect(() => {
    const fetchCurrentUser = async () => {
      const { data: { user } } = await supabase.auth.getUser();
      setUser(user);
    };
    fetchCurrentUser();
  }, [supabase]);

  const handleLogin = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault(); // 阻止默认表单提交行为
    setIsLoading(true);
    
    const formData = new FormData(e.currentTarget);
    const email = formData.get('email') as string;
    const password = formData.get('password') as string;

    try {
      const { error } = await supabase.auth.signInWithPassword({
        email,
        password,
      });
      
      if (error) throw error;
      // 登录成功后的逻辑,比如跳转首页
    } catch (error) {
      toast.error("Login failed!");
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <main className="h-full w-full flex flex-col justify-between items-center pt-56 pb-24 z-20 relative ">
      <h1 className="font-NAM text-white text-9xl">title</h1>
      <form className="flex flex-col w-80" onSubmit={handleLogin}>
        <Input
          name="email"
          className="mb-5"
          fullWidth
          placeholder="Email"
          type="text"
        />
        <div className="w-full mb-5">
          <Input
            name="password"
            className="mb-1"
            fullWidth
            placeholder="Password"
            type="password"
          />
          <div className="flex justify-between text-white underline text-sm">
            <Link className="hover:text-white" href="/register">
              Regístrate
            </Link>
            <Link className="hover:text-white" href="/">
              Olvidaste tu contraseña?
            </Link>
          </div>
        </div>
        <Button type="submit" uppercase={true} filled={true} disabled={isLoading}>
          {isLoading ? 'Cargando...' : 'Inicia sesión'}
        </Button>
      </form>
    </main>
  );
}

关键修改点说明

  • 'use client'指令:明确组件运行在客户端,解锁React Hooks、客户端交互等能力。
  • 用户信息获取:通过useEffect在客户端执行用户查询,确保能读取到浏览器中的Auth会话。
  • 表单提交:使用onSubmit替代服务端formAction,手动处理表单数据与登录逻辑,避免环境冲突。
  • 加载状态优化:给按钮添加disabled属性,防止用户重复提交表单。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 00:20:01