Supabase登录后Navbar无法实时显示token_count问题排查
问题描述
在React+Supabase项目中,从users表获取token_count时遇到以下问题:
- 用户登录后Navbar无法立即显示当前用户的token_count,必须刷新页面才会更新
- 登录后会显示上一位登录用户的token_count,刷新后才切换为当前用户的值
- 该token_count还需在HomePage和弹窗中使用,需要实现登录后立即显示正确值的效果
现有代码
import HomePage from '../HomePage/HomePage'; import LandingPage from '../LandingPage/LandingPage'; import AuthPage from '../AuthPage/AuthPage'; import MyAccountPage from '../MyAccountPage/MyAccountPage'; import NavBar from '../NavBar/NavBar'; import { BrowserRouter as Router, Routes, Route} from 'react-router-dom'; import { useEffect, useState } from 'react'; import './App.css' import supabase from '../../supabaseClient'; export type TableResults = { item_id: string; created_at: string; title: string; image: string; user_id: string; username: string; token_count?: number; } export default function App() { const [items, setItems] = useState<TableResults[]>([]); const [filteredItems, setFilteredItems] = useState<TableResults[]>(items); const [user, setUser] = useState<any>(null); const [tokenCount, setTokenCount] = useState<number|null>(null); useEffect(() => { getItems(); }, []); useEffect(() => { setFilteredItems(items); }, [items]); async function getItems() { let { data: itemsData, error: itemsError } = await supabase .from('items') .select('item_id, created_at, title, image, user_id'); let { data: usersData, error: usersError } = await supabase .from('users') .select('user_id, username, token_count'); if (itemsError) console.error('Items Error: ', itemsError); if (usersError) console.error('Users Error: ', usersError); if (!itemsError && !usersError && itemsData && usersData) { const transformedData = itemsData.map(item => { const user = usersData?.find(user => user.user_id === item.user_id); return { ...item, username: user ? user.username : null, }; }); console.log('Transformed Data: ', transformedData); setItems(transformedData); } } // this is to check that the items are being pulled from the database console.log("see items below...") console.log(items) useEffect(() => { const fetchUserTokenCount = async () => { console.log('Fetching user token count'); try { // Get the user object const { data: { user } } = await supabase.auth.getUser(); if (!user) { console.log('User not found'); return; } // Extract the user_id from the user object const user_id = user.id; // Query the users table using the user_id const { data, error } = await supabase .from('users') .select('token_count') .eq('user_id', user_id); if (error) { // Handle the error if the query fails console.error('Error retrieving user token count:', error); } else { if (data.length > 0) { // A match was found, extract the token_count value const { token_count } = data[0]; // Use the token_count value as needed setTokenCount(token_count); // Set the token count in the state } else { // No match was found console.log('Token count not found for the user.'); } } } catch (error) { // Handle any other errors that occur console.error('Error retrieving user token count:', error); } }; fetchUserTokenCount(); }, [user]); // Add user as a dependency return ( <Router> <div className="App"> <NavBar tokenCount={tokenCount} user={user} /> <Routes> <Route path = "/login" element = {<AuthPage/>} /> <Route path = "/" element = {<LandingPage items={items} setItems={setItems} setFilteredItems={setFilteredItems} filteredItems={filteredItems}/>} /> <Route path = "/home" element = {<HomePage items={items} setItems={setItems} setFilteredItems={setFilteredItems} filteredItems={filteredItems} tokenCount={tokenCount} setTokenCount={setTokenCount}/>} /> <Route path = "/myaccount" element = {<MyAccountPage/>} /> </Routes> </div> </Router> ); }
解决方案
问题根源在于没有实时监听Supabase的认证状态变化,导致user状态未及时更新,进而无法触发tokenCount的重新获取,同时旧用户的tokenCount状态未被清理。以下是修复步骤:
1. 监听Supabase认证状态变化,实时更新user状态
替换原有的user相关逻辑,使用Supabase的onAuthStateChange监听登录、登出、用户变更等事件,确保user状态实时同步:
useEffect(() => { // 初始化获取当前用户 const getCurrentUser = async () => { const { data: { user } } = await supabase.auth.getUser(); setUser(user); }; getCurrentUser(); // 监听认证状态变化 const authListener = supabase.auth.onAuthStateChange((event, session) => { setUser(session?.user ?? null); }); // 组件卸载时移除监听 return () => authListener.unsubscribe(); }, []);
2. 优化tokenCount获取逻辑,清理旧状态
修改获取tokenCount的useEffect,在用户不存在时重置tokenCount,避免残留旧数据:
useEffect(() => { const fetchUserTokenCount = async () => { if (!user) { // 用户登出或未登录时,重置tokenCount setTokenCount(null); return; } try { const { data, error } = await supabase .from('users') .select('token_count') .eq('user_id', user.id) .single(); // 使用single()确保返回单个用户数据,避免数组处理 if (error) { console.error('获取token_count失败:', error); setTokenCount(null); } else { setTokenCount(data.token_count); } } catch (error) { console.error('获取token_count异常:', error); setTokenCount(null); } }; fetchUserTokenCount(); }, [user]);
3. 确保AuthPage登录后触发状态更新
如果AuthPage使用Supabase的登录方法(如signInWithPassword),登录成功后无需额外操作,因为onAuthStateChange会自动捕获状态变化并更新user,进而触发tokenCount的重新获取。
完整修改后的App组件核心代码
export default function App() { const [items, setItems] = useState<TableResults[]>([]); const [filteredItems, setFilteredItems] = useState<TableResults[]>(items); const [user, setUser] = useState<any>(null); const [tokenCount, setTokenCount] = useState<number|null>(null); useEffect(() => { getItems(); }, []); useEffect(() => { setFilteredItems(items); }, [items]); async function getItems() { // 原getItems逻辑保持不变 } // 新增:监听认证状态变化 useEffect(() => { const getCurrentUser = async () => { const { data: { user } } = await supabase.auth.getUser(); setUser(user); }; getCurrentUser(); const authListener = supabase.auth.onAuthStateChange((event, session) => { setUser(session?.user ?? null); }); return () => authListener.unsubscribe(); }, []); // 优化后的tokenCount获取逻辑 useEffect(() => { const fetchUserTokenCount = async () => { if (!user) { setTokenCount(null); return; } try { const { data, error } = await supabase .from('users') .select('token_count') .eq('user_id', user.id) .single(); if (error) { console.error('获取token_count失败:', error); setTokenCount(null); } else { setTokenCount(data.token_count); } } catch (error) { console.error('获取token_count异常:', error); setTokenCount(null); } }; fetchUserTokenCount(); }, [user]); // 原return部分保持不变 }
通过以上修改,登录后Auth状态变化会实时更新user,进而触发tokenCount的重新获取,Navbar会立刻显示当前用户的正确token_count,同时登出时会清空旧状态,避免显示上一位用户的数据。
内容的提问来源于stack exchange,提问作者user22115305
相关产品推荐
相关产品推荐

