React Query中如何实现嵌套/条件链式API调用?
React Query 实现条件链式API调用的正确姿势
你的核心问题是违反了React Hook「只能在顶层调用」的规则,下面是几种符合规范且贴合需求的实现方式:
方案一:顶层声明所有Hook,通过enabled控制执行时机
把所有需要用到的React Query Hook都放在组件/自定义Hook的顶层,利用enabled选项控制它们是否触发,再根据条件选择对应结果返回:
function getCarDetails(car: CarSummary): UseQueryResult<CarDetails> { // 顶层声明所有查询,仅当车型匹配时才启用对应前置查询 const hondaQuery = useHondaData(car, { enabled: car.make === 'honda' }); const teslaQuery = useTeslaData(car, { enabled: car.make === 'tesla' }); // 根据车型匹配对应的前置查询结果 const preQueryResult = car.make === 'honda' ? hondaQuery : car.make === 'tesla' ? teslaQuery : null; // 前置查询出错时直接返回错误结果 if (preQueryResult?.isError) { return preQueryResult as unknown as UseQueryResult<CarDetails>; } // 调用详情查询:通用车型直接执行,品牌车型等前置数据返回后再执行 return useCarDetailsData( { x: preQueryResult?.data?.y || 'generic' }, { enabled: !preQueryResult || !!preQueryResult.data } ); }
这种方式严格遵守Hook规则,逻辑和原代码完全对齐,前置查询只会在对应车型匹配时才发起请求,详情查询会自动等待前置数据就绪后再触发。
方案二:在单个useQuery中嵌套API调用
如果不想声明多个Hook,可以把整个链式逻辑封装到一个useQuery的queryFn中,只需要顶层调用一个Hook即可:
function getCarDetails(car: CarSummary): UseQueryResult<CarDetails> { return useQuery({ queryKey: ['carDetails', car], queryFn: async () => { let xValue = 'generic'; if (car.make === 'honda') { const hondaData = await fetchHondaData(car); // 这里用直接的API请求函数,而非useHondaData Hook xValue = hondaData.y; } else if (car.make === 'tesla') { const teslaData = await fetchTeslaData(car); // 同理,使用底层异步请求函数 xValue = teslaData.y; } return fetchCarDetailsData({ x: xValue }); // 最终调用详情API }, }); }
注意:这里必须使用直接封装的API请求函数(比如基于fetch/axios的异步函数),不能用对应的useHondaData类Hook——因为Hook不允许在异步函数内部调用。这种方式把所有逻辑收敛到一个查询中,错误会由React Query统一管理(前置API报错时,整个查询会直接标记为错误状态)。
方案三:使用useQueries管理多查询(复杂场景扩展)
如果需要更细粒度地跟踪多个查询状态,可以用useQueries批量管理,不过对你的需求来说稍显冗余,适合复杂场景参考:
function getCarDetails(car: CarSummary): UseQueryResult<CarDetails> { const queries = useQueries({ queries: [ { queryKey: ['hondaData', car], queryFn: () => fetchHondaData(car), enabled: car.make === 'honda' }, { queryKey: ['teslaData', car], queryFn: () => fetchTeslaData(car), enabled: car.make === 'tesla' }, { queryKey: ['carDetails', car], queryFn: async () => { const preData = car.make === 'honda' ? queries[0].data : car.make === 'tesla' ? queries[1].data : null; return fetchCarDetailsData({ x: preData?.y || 'generic' }); }, enabled: car.make !== 'honda' || !!queries[0].data, }, ], }); // 处理前置查询的错误 if ((car.make === 'honda' && queries[0].isError) || (car.make === 'tesla' && queries[1].isError)) { return (car.make === 'honda' ? queries[0] : queries[1]) as unknown as UseQueryResult<CarDetails>; } // 返回最终的详情查询结果 return queries[2]; }
内容的提问来源于stack exchange,提问作者Aximili
相关产品推荐
相关产品推荐

