React Hooks:如何在异步获取用户后有条件调用自定义Hook执行GraphQL查询
解决useQuery需等待用户信息的Hook规则冲突问题
这是个非常常见的React Hooks规则和数据依赖查询的矛盾场景,我来给你梳理下最合理的解决方案:
核心思路:利用useQuery的内置控制参数
React Hooks规则要求所有Hook必须在组件/自定义Hook的顶层作用域调用,不能放在条件判断、循环或者useEffect这类回调里。但好在主流的GraphQL Hook库(比如Apollo Client)都提供了内置参数来控制查询的执行时机,完全不需要自己用条件包裹Hook调用。
步骤1:优化你的useGetUser Hook(可选但推荐)
你原来的useGetUser初始状态设为false,容易和用户对象的布尔判断混淆(比如用户对象本身可能被转成布尔值),建议改成null来明确表示"未加载完成"的状态,同时加上错误处理:
function useGetUser() { // 用null表示未加载,undefined或false可能产生歧义 const [user, setUser] = useState(null); useEffect(() => { async function getUser() { try { const session = await Auth.currentSession(); setUser(session); } catch (error) { // 处理获取用户失败的情况,比如登录过期、未登录 console.error('获取用户会话失败:', error); setUser(null); } } // 只有当user为null时才触发,避免无限循环 if (user === null) { getUser(); } }, [user]); return user; }
步骤2:用enabled参数控制useQuery的执行时机
直接在自定义Hook的顶层调用useQuery,通过enabled参数设置为!!user(当user存在时才为true),这样就能实现"等待用户信息加载完成后再执行查询"的需求:
// 假设你用的是Apollo Client,其他库类似(比如urql也有类似的pause参数) import { useQuery, gql } from '@apollo/client'; // 建议用gql标签定义查询,而不是直接传字符串 const YOUR_GRAPHQL_QUERY = gql` query YourQueryName { # 你的查询内容 blablabla } `; function useGraphQLQuery() { const user = useGetUser(); // 直接在顶层调用useQuery,用enabled控制执行时机 const { data, loading, error } = useQuery(YOUR_GRAPHQL_QUERY, { // 当user存在时才启用查询 enabled: !!user, // 把用户token放到请求头里 context: { headers: { authorization: user?.getAccessToken()?.getJwtToken() || '' } }, // 如果需要传递变量给查询,也可以在这里动态设置 // variables: { userId: user?.id } }); // 返回查询结果,供使用这个Hook的组件调用 return { data, loading, error }; }
为什么这样可行?
- 符合Hook规则:useQuery在自定义Hook的顶层调用,没有被任何条件或回调包裹,完全满足React的Hook规范。
- 自动控制查询时机:当user从
null变成有效的用户对象时,enabled会从false变为true,useQuery会自动触发查询;如果user一直是null,查询会被跳过。 - 简洁易维护:不需要额外的useEffect来手动触发查询,逻辑全部由useQuery内置的机制处理,减少了出错的可能。
如果你的GraphQL库不是Apollo Client,比如urql,它对应的控制参数是pause(设置为!user即可),核心思路都是一样的:利用Hook本身提供的条件执行参数,而不是自己用条件判断来包裹Hook调用。
内容的提问来源于stack exchange,提问作者GuillaumeC
相关产品推荐
相关产品推荐

