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
相关产品推荐
相关产品推荐

