如何将useEffect获取的数据作为参数传入useQuery的variables?
问题根源
你的错误触发原因和方案缺陷主要来自两个核心问题:
- 违反React Hook调用规则:将
useQuery放在if (profileTypeA)条件块内,Hook调用顺序必须在组件顶层保持稳定,嵌套在条件/循环内会引发不可预期的bug,这也是你把useQuery移出条件块后错误依然存在的原因之一。 - 未控制
useQuery的执行时机:useEffect的执行时机晚于组件首次渲染,首次渲染时useQuery就会默认发起请求,此时user还是初始空对象,variables传入的id为undefined,自然会触发参数错误的回调。
最优解决方案
useQuery提供了**enabled配置项**,专门用于控制查询的触发时机,只要enabled值为false,查询就不会发起,完美适配动态参数的场景,不需要手动维护多余的状态和请求判断。
最小改动方案(保留现有useEffect逻辑)
修正后的代码如下:
const router = useRouter(); const { id } = router.query; // 初始值设为null更容易判断是否已加载到用户数据 const [user, setUser] = useState(null); const [profileTypeA, setProfileTypeA] = useState(false); // 1. 把useQuery移到组件顶层,不要放在条件块内 const { loading: queryLoading, error: queryError, data: queryData } = useQuery( QUERY_FOR_USER_TYPE_A, { variables: { id: user?.userId }, // 2. 只有满足两个条件才发起查询:是A类型用户 + 用户ID已存在 enabled: profileTypeA && !!user?.userId, } ); const userData = queryData?.moreData; useEffect(() => { async function getUser() { if (!router.isReady) return; const userDb = await getUserFromDb(id); if (!userDb) { return <Error statusCode={404} />; } const userPayload = userDb.data.payload; setUser(userPayload); if (userPayload.type === 'A') setProfileTypeA(true); } getUser(); return () => { consola.success('Cleanup profile page'); }; // 注意:要把id加入依赖数组,id变化时会重新获取用户数据 }, [router.isReady, id]); // 渲染逻辑处理 if (!router.isReady || !user) return null; if (profileTypeA) { if (queryLoading) return null; if (queryError) return <Error statusCode={404} />; } // 后续你的页面渲染逻辑
更简洁的优化方案
你的getUserFromDb请求本身也可以用useQuery实现,不需要手动写useEffect维护状态,逻辑更统一:
const router = useRouter(); const { id } = router.query; // 第一个查询:获取基础用户数据 const { data: userDb, loading: userLoading, error: userError } = useQuery( ['user', id], () => getUserFromDb(id), { // router准备好且id存在时才发起请求 enabled: router.isReady && !!id, } ); const user = userDb?.data?.payload; const profileTypeA = user?.type === 'A'; // 第二个查询:获取A类型用户的额外数据 const { loading: queryLoading, error: queryError, data: queryData } = useQuery( QUERY_FOR_USER_TYPE_A, { variables: { id: user?.userId }, enabled: profileTypeA && !!user?.userId, } ); const userData = queryData?.moreData; // 统一处理加载和错误状态 if (userLoading) return null; if (userError || !user) return <Error statusCode={404} />; if (profileTypeA) { if (queryLoading) return null; if (queryError) return <Error statusCode={404} />; } // 后续你的页面渲染逻辑
方案说明
enabled配置是React Query官方推荐的动态参数/依赖查询的标准实现,不会发起无效请求,也不会触发不必要的错误回调,完全符合你的预期逻辑:
- 先等待用户基础数据加载完成,判断用户类型
- 条件满足时自动触发第二个查询,传入正确的用户ID参数
内容的提问来源于stack exchange,提问作者benjamin852
相关产品推荐
相关产品推荐

