如何向React Query自定义Hook传递参数?
问题分析
你的自定义Hook useUserInfo 将 token 作为Hook的参数,但调用 refetch 时无法修改Hook的参数(Hook参数仅在组件渲染阶段生效),导致查询函数始终使用初始化时的token(此处初始化未传值,因此为undefined)。同时,refetch 的参数会直接传递给查询函数,而非自定义Hook本身,所以你之前的写法无法将token传递给fetchUserInfo。
解决方案
方案一:通过组件状态管理token,让React Query自动触发查询(推荐)
利用查询键的变化自动触发新查询,符合React Query的设计理念:
- 修改自定义Hook,将
token加入查询键,确保token变化时自动执行新查询:
export const useUserInfo = (enabled, token) => { return useQuery( ["users-info", token], // token变化时,React Query判定为新查询,自动重新执行 () => fetchUserInfo(token), { enabled: enabled, // 仅当token存在时启用查询 }, ); };
- 在组件中管理token状态,获取到token后更新状态,useQuery会自动处理后续查询:
const Auth = () => { const [token, setToken] = useState(null); const { data: userInfo, isSuccess, isError, error } = useUserInfo(!!token, token); const dispatch = useDispatch(); const navigate = useNavigate(); // 用户信息获取成功后执行后续操作 useEffect(() => { if (isSuccess && userInfo) { dispatch({ type: "SET_USER", payload: userInfo }); navigate("/"); location.reload(); } }, [isSuccess, userInfo, dispatch, navigate]); // 处理查询错误 useEffect(() => { if (isError) { console.error(error); } }, [isError, error]); const handleLoginPopup = async () => { try { const newToken = "abcd121212"; // 实际为登录接口返回的token setToken(newToken); } catch (error) { console.error(error); } }; return ( <button onClick={handleLoginPopup}>登录</button> ); };
方案二:通过refetch传递参数给查询函数(适合无需按token缓存的场景)
如果确实需要手动调用refetch传递token,可以修改查询函数接收refetch的参数:
- 调整自定义Hook,让查询函数读取
refetch传入的参数:
export const useUserInfo = (enabled) => { return useQuery( ["users-info"], // 无需按token缓存时,查询键固定 ({ refetchArg }) => { const { token } = refetchArg; if (!token) { throw new Error("Token is required"); } return fetchUserInfo(token); }, { enabled: enabled, // 初始不启用查询 }, ); };
- 在组件中调用
refetch时直接传递token:
const Auth = () => { const { refetch } = useUserInfo(false); const dispatch = useDispatch(); const navigate = useNavigate(); const handleLoginPopup = async () => { try { const token = "abcd121212"; // 调用refetch并传递token参数 const { data: userInfo } = await refetch({ token }); dispatch({ type: "SET_USER", payload: userInfo }); navigate("/"); location.reload(); } catch (error) { console.error(error); } }; return ( <button onClick={handleLoginPopup}>登录</button> ); };
注意:方案二的查询键固定,不同token的结果会覆盖同一缓存。若需要为每个token单独缓存数据,优先使用方案一。
内容的提问来源于stack exchange,提问作者ganesh kaspate
相关产品推荐
相关产品推荐

