React中如何仅在Token存在时调用useQuery?解决无限重渲染问题
解决React "Too many re-renders" 无限重渲染问题
问题原因
你遇到的无限重渲染,核心问题出在组件渲染的顶层直接调用了setState:
- 组件每次渲染时,都会执行
localStorage.getItem("Token")的判断逻辑,只要Token存在,就调用setIsEnabledApi(true) - 调用
setState会强制组件重新渲染,重新渲染时又会再次执行这段判断逻辑,再次触发setState,形成无限循环
解决方案
1. 用useEffect包裹Token判断逻辑
把Token的判断和状态更新放到useEffect里,只在组件挂载或Token变化时执行,避免每次渲染都触发状态更新:
// header.jsx import { useState, useEffect } from 'react'; const Header = () => { const [isUserExists, setIsUserExists] = useState(); const [userName, setUserName] = useState(""); const [isEnabledApi, setIsEnabledApi] = useState(false); const token = localStorage.getItem("Token"); // 仅在Token变化时更新接口启用状态 useEffect(() => { if (token) { console.log('token exists') setIsEnabledApi(true); } else { console.log('no token') setIsEnabledApi(false); } }, [token]); // 依赖token,只有token变化时才重新执行
2. 优化useQuery的自定义hook实现
你的apiAuth函数本质是封装useQuery,但当前写法不符合React自定义hook规范(自定义hook必须以use开头),且无需把setState函数传入hook,建议重构为标准自定义hook:
// apiAuth.js import { useQuery } from '@tanstack/react-query'; // 重命名为useApiAuth,符合自定义hook命名规范 export const useApiAuth = (isEnabled) => { return useQuery({ queryKey: ['isUserExist'], queryFn: () => { console.log('calling query function') return IsLoggedIn(); // axios.get("/Auth"); }, enabled: isEnabled, }); };
3. 在组件中处理接口结果
在Header组件中使用重构后的hook,通过监听接口结果的状态来更新本地状态:
// header.jsx 继续补充 import { useApiAuth } from './apiAuth'; // ... 前面的状态定义和useEffect代码 ... // 使用自定义hook调用接口 const { data: loginInfo, isSuccess, isError } = useApiAuth(isEnabledApi); // 根据接口结果更新本地状态 useEffect(() => { if (isSuccess && loginInfo) { setIsUserExists(true); setUserName(loginInfo.data.userName); setIsEnabledApi(false); // 验证完成后禁用接口,避免重复调用 } if (isError) { setIsUserExists(false); setIsEnabledApi(false); } }, [isSuccess, isError, loginInfo]); return( <> {isUserExists ? <UserButton /> : <LoginButton />} </> ) };
额外优化建议
- React Query默认会缓存查询结果,只要
queryKey不变,不会重复调用接口,因此可以去掉setIsEnabledApi(false)的逻辑,让React Query自动处理缓存 - 初始化
isUserExists时可以设为null,用来区分“未验证”和“验证失败”状态,避免初始渲染时直接显示登录按钮
内容的提问来源于stack exchange,提问作者Liam neesan
相关产品推荐
相关产品推荐

