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

React 19: 如何在UserContext中使用use Hook与Suspense实现鉴权?

React 19 use Hook + Suspense 改造鉴权Context方案

问题核心

直接在Context里写const { user } = use(getUser())会触发无限循环,原因是每次组件渲染时,getUser()都会返回一个新的Promise实例,而use Hook会依赖这个Promise的引用,引用变化就会重新执行,导致组件反复渲染。

这个场景完全适合用React 19的use Hook和Suspense特性,关键是要保证Promise的稳定性,同时支持登录后更新用户状态。


解决方案:稳定Promise + 触发刷新机制

我们可以通过useMemo缓存Promise实例,只在需要重新获取用户时(比如登录/登出后)更新依赖,避免无限循环。

1. 改造UserProvider

const UserProvider = ({ children }: { children: React.ReactNode }) => {
  // 用计数器控制用户信息刷新,登录/登出时更新
  const [refreshTrigger, setRefreshTrigger] = useState(0);

  // 仅当refreshTrigger变化时,重新创建getUser的Promise
  const userPromise = useMemo(() => getUser(), [refreshTrigger]);

  // 用use Hook读取Promise结果,自动触发Suspense
  const { user } = use(userPromise);

  const login = async (userName: string, password: string) => {
    try {
      await authlogin(userName, password);
      // 登录成功后触发用户信息刷新
      setRefreshTrigger(prev => prev + 1);
    } catch (e) {
      // 保留原错误处理逻辑
    }
  };

  const logout = () => {
    // 可在此调用登出API,然后触发刷新
    setRefreshTrigger(prev => prev + 1);
  };

  const isAuthenticated = user !== null;

  return (
    <UserContext value={{ user, isAuthenticated, login, logout }}>
      {children}
    </UserContext>
  );
};

2. 简化RequireAuth组件

不再需要处理isLoading状态,因为Suspense会自动接管加载过程:

const RequireAuth = ({ children }: { children: React.ReactNode }) => {
  const { isAuthenticated } = useUserContext();

  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }

  return children;
};

3. 配置Suspense边界

在路由层面包裹需要鉴权的页面,指定加载 fallback:

function App() {
  return (
    <UserProvider>
      <Routes>
        <Route path="/login" element={<LoginPage />} />
        <Route
          path="/"
          element={
            <Suspense fallback={<div>Loading...</div>}>
              <RequireAuth>
                <Dashboard />
              </RequireAuth>
            </Suspense>
          }
        />
        {/* 其他需要鉴权的路由同理 */}
      </Routes>
    </UserProvider>
  );
}

关键注意事项

  • use Hook必须在组件或自定义Hook的顶层调用,不能放在条件判断、循环或嵌套函数中。
  • 错误处理:如果getUser()抛出错误,需要用React的ErrorBoundary组件捕获,use Hook会将错误向上抛给最近的错误边界。
  • 登出逻辑:如果后端有登出API,建议在logout函数中先调用API,再更新refreshTrigger。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 11:57:04