如何在react-query中正确实现useQueries以处理同组件多查询
问题根因
- 最初的双
useQuery方案报错核心是isLoading和error的判断逻辑完全写反:
你用了&&逻辑,需要两个查询同时加载才会显示Loading,只要其中一个查询先完成,就会跳过Loading判断进入渲染逻辑,此时另一个还未返回的查询对应的数据是undefined,子组件调用filter方法自然报错;同理error用&&也会导致只要一个查询正常、一个查询报错的场景下,直接进入渲染逻辑,报错数据为undefined。 - 改用
useQueries后报错是因为你违反了两个规则:
- React Hook只能在组件顶层或其他自定义Hook中调用,你将自定义Hook
useData2的调用结果传给queryFn属于在普通函数上下文中调用Hook,本身就是不合法的 queryFn要求传入一个可执行的异步函数,你直接执行useData2后拿到的是useQuery返回的结果对象,自然会报queryFn is not a function的错误。
另外你额外用useState存储react-query返回的数据属于冗余操作,react-query本身已经内置了响应式的数据状态管理,不需要额外用本地state同步,反而会引入状态更新时机不一致的问题。
方案1:修复原双useQuery方案(更简单,推荐)
首先修改自定义HookuseData,去掉冗余的setData传参,直接返回查询结果:
export function useData(queryId, chartId) { return useQuery( queryId, () => fetchData(chartId, "models").then((resp) => resp.Item.data) ); }
然后修改组件内的逻辑,修正Loading和错误判断:
export default function Component() { const { data: barData, error: errorBar, isLoading: loadingBar } = useData( "barQuery", "BAR_TEST_SINGLE" ); const { data: lineData, error: errorLine, isLoading: loadingLine } = useData( "lineQuery", "LINE_TEST" ); // 任意一个查询加载中就显示Loading const isLoading = loadingLine || loadingBar; // 任意一个查询报错就显示错误页 const error = errorLine || errorBar; if (isLoading) return <LoadingSpinner title={title} />; if (error) return <InvalidStateAPI description={error.message} title={title} />; return ( <> <Line data={lineData} /> <Bar data={barData} /> </> ); }
方案2:useQueries实现方案
如果要统一管理多个查询,也可以用useQueries实现,不需要嵌套自定义Hook,直接写查询逻辑即可:
export default function Component() { const results = useQueries([ { queryKey: ["barQuery"], queryFn: () => fetchData("BAR_TEST_SINGLE", "models").then(resp => resp.Item.data), }, { queryKey: ["lineQuery"], queryFn: () => fetchData("LINE_TEST", "models").then(resp => resp.Item.data), }, ]); const isLoading = results.some(res => res.isLoading); const error = results.find(res => res.error)?.error; const [barData, lineData] = results.map(res => res.data); if (isLoading) return <LoadingSpinner title={title} />; if (error) return <InvalidStateAPI description={error.message} title={title} />; return ( <> <Line data={lineData} /> <Bar data={barData} /> </> ); }
内容的提问来源于stack exchange,提问作者mmz
相关产品推荐
相关产品推荐

