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

React+Supabase认证:页面重载后Context用户ID丢失问题排查

问题

我正在搭建一个React应用,处于用户认证功能的初期配置阶段。借助数据库服务Supabase,用户管理和会话管理的实现较为简单,但在根据用户登录状态条件渲染应用组件时遇到了问题——比如需要根据用户是否登录渲染不同的导航栏。

我创建了一个自定义hook useCurrentUser来封装Supabase的登录相关逻辑,并尝试创建Context以便在应用其他部分引用。初始登录时一切正常:Context中能看到用户ID,导航栏也能根据登录状态正确渲染,但页面重载后Context值会被清空。

以下是我初始化Context的TypeScript代码:

import React, { useEffect } from "react";
import { createContext, useContext, useState } from "react";
import useCurrentUser from "../hooks/useCurrentUser";
import supabase from "../supabaseClient";

type TestT = [String, React.Dispatch<React.SetStateAction<String>>];

const UserContext = createContext<TestT>(undefined!);

export function useUser() {
  return useContext(UserContext);
}

export function UserProvider({ children }: any) {
  console.log("IN USER PROVIDER");
  console.log(useCurrentUser());
  const [test, setTest] = useState(useCurrentUser()!);
  return (
    <UserContext.Provider value={[test, setTest]}>
      {children}
    </UserContext.Provider>
  );
}

export { UserContext };

问题在于:我将Provider的值设置为一个状态变量,其默认值来自useCurrentUser hook。但页面重载后,React DevTools显示'test'状态及Provider值变为undefined。令人困惑的是,在设置状态前打印useCurrentUser(),能输出有效的用户ID,为何状态和Provider值无法正确获取该值?请问我哪里出错了?如何让页面重载后Context仍能保留用户ID?


解决方案

问题根源

  1. useState初始值仅执行一次:React中useState的初始值只会在组件首次渲染时赋值一次。页面重载后,useCurrentUser()大概率是异步获取用户信息——你打印时看到的有效值,其实是组件渲染完成后hook异步更新的结果,而useState的初始值是在渲染初期获取的,此时用户数据还未返回,因此初始化为undefined。
  2. 未同步hook的更新:useCurrentUser内部如果有状态变化(比如从Supabase拿到用户信息后更新),你的UserProvider没有监听这个变化来同步更新test状态,导致Context无法获取最新的用户数据。

修复代码

修改UserProvider,通过useEffect监听useCurrentUser的返回值变化,同步更新Context的状态:

import React, { useEffect, useState } from "react";
import { createContext, useContext } from "react";
import useCurrentUser from "../hooks/useCurrentUser";

// 优化类型定义,用基本类型string而非包装类型String,指定安全默认值
type UserContextType = [string | null, React.Dispatch<React.SetStateAction<string | null>>];
const UserContext = createContext<UserContextType>([null, () => {}]);

export function useUser() {
  return useContext(UserContext);
}

// 给children指定明确类型,避免any
export function UserProvider({ children }: { children: React.ReactNode }) {
  const currentUserId = useCurrentUser();
  const [test, setTest] = useState<string | null>(currentUserId);

  // 监听currentUserId的变化,同步更新Context状态
  useEffect(() => {
    setTest(currentUserId);
  }, [currentUserId]);

  return (
    <UserContext.Provider value={[test, setTest]}>
      {children}
    </UserContext.Provider>
  );
}

export { UserContext };

额外优化建议

  • 处理异步加载状态:在useCurrentUser中可以返回null或加载状态标识,Provider中可据此处理用户数据未加载完成的情况,避免UI闪烁。
  • 简化Context逻辑(可选):如果不需要手动修改用户ID状态,可直接将useCurrentUser的返回值放入Context,省去中间状态:
// 简化版Provider
export function UserProvider({ children }: { children: React.ReactNode }) {
  const currentUserId = useCurrentUser();
  return (
    <UserContext.Provider value={currentUserId}>
      {children}
    </UserContext.Provider>
  );
}

内容的提问来源于stack exchange,提问作者Luke Sharon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 05:21:56