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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 17:32:04