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> ); }
关键注意事项
useHook必须在组件或自定义Hook的顶层调用,不能放在条件判断、循环或嵌套函数中。- 错误处理:如果
getUser()抛出错误,需要用React的ErrorBoundary组件捕获,useHook会将错误向上抛给最近的错误边界。 - 登出逻辑:如果后端有登出API,建议在
logout函数中先调用API,再更新refreshTrigger。
内容的提问来源于stack exchange,提问作者Ganbin
相关产品推荐
相关产品推荐

