NextJS 14 + Supabase Auth:实现认证后UI自动更新
解决方案:修复NextJS 14 + Supabase Auth UI自动更新问题
问题根源分析
你的代码存在几个核心问题导致UI无法自动更新:
- Supabase客户端实例不稳定,每次组件渲染都会创建新实例,旧实例的监听无法捕获状态变化
- 未正确清理认证状态监听,导致内存泄漏和状态逻辑混乱
- 状态更新逻辑只覆盖部分认证事件,遗漏会话刷新等场景
- 多余的
setTimeout可能延迟状态更新
修复后的完整代码
'use client' import { useEffect, useState, useMemo } from 'react'; import { useRouter } from 'next/navigation'; import { createClient } from '@/utils/supabase/client' export default function Header() { const router = useRouter() // 用useMemo缓存Supabase实例,避免每次渲染重新创建 const supabase = useMemo(() => createClient(), []); const [userIsLogged, setuserIsLogged] = useState<boolean>(false) useEffect(() => { // 订阅认证状态变化,获取取消订阅函数 const unsubscribe = supabase.auth.onAuthStateChange((event, session) => { console.log('onAuthStateChange', event, session); // 直接根据会话是否存在更新状态,覆盖所有认证相关场景 setuserIsLogged(!!session); }); // 初始化加载当前会话状态 const loadSession = async () => { const { data: { session }, error } = await supabase.auth.getSession(); if (error) console.error(error); setuserIsLogged(!!session); }; loadSession(); // 组件卸载时自动清理监听 return unsubscribe; }, [supabase]); return ( <div> {userIsLogged ? ( <form action="/auth/signout" method="post"> <button type="submit">Sign Out</button> </form> ) : ( <button onClick={() => router.push('/auth')}>Log in</button> )} </div> ); }
关键修复点说明
稳定Supabase实例
用useMemo缓存createClient()的返回值,确保组件生命周期内始终使用同一个客户端实例,避免监听绑定到旧实例导致的事件丢失。正确清理监听
将onAuthStateChange返回的unsubscribe函数作为useEffect的返回值,组件卸载时自动取消订阅,防止内存泄漏和重复监听。全面的状态更新逻辑
不再只判断SIGNED_IN和SIGNED_OUT事件,直接根据session是否存在更新状态,覆盖TOKEN_REFRESHED等会话更新场景,确保所有认证状态变化都能触发UI更新。移除多余的
setTimeout
直接在监听回调内更新状态,避免延迟或丢失状态变更的情况。
内容的提问来源于stack exchange,提问作者JV Lobo
相关产品推荐
相关产品推荐

