如何在 react-query 中正确实现 useQueries?

How to properly implement useQueries in react-query?

我正在使用 react-query 在同一个 React 组件中进行两个单独的查询。我最初尝试使用两个 useQuery 钩子:

export default function Component() {
  const [barData, setBarData] = useState();
  const [lineData, setLineData] = useState();
  const { error: errorBar, isLoading: loadingBar } = useData(
    "barQuery",
    "BAR_TEST_SINGLE",
    setBarData
  );
  const { error: errorLine, isLoading: loadingLine } = useData(
    "lineQuery",
    "LINE_TEST",
    setLineData
  );

  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} />
    </>
  );
}

这是从另一个文件导入的useData的内容:

export function useData(queryId, chartId, setData) {
  return useQuery(
    queryId,
    () =>
      fetchData(chartId, "models").then((resp) => {
        setData(resp.Item.data);
      })
  );
}

fetchData 是一个查询 AWS DDB table 的函数。我很高兴 post 该功能,但为了简洁起见,我目前将其排除在外。

呈现 Component 导致此错误:TypeError: Cannot read properties of undefined (reading 'filter')。我怀疑抛出此错误是因为组件没有及时获取其数据以进行渲染。我认为这可以通过添加 const isLoading = loadingLine && loadingBar; 来解决,如 this post 中所建议的那样,但事实并非如此。

最后,关于 SO answer, I decided to use useQueries. The documentation的推荐比较稀疏,不过推荐如下格式:

const results = useQueries([
   { queryKey: ['post', 1], queryFn: fetchPost },
   { queryKey: ['post', 2], queryFn: fetchPost },
 ])

我将我的原始代码修改为以下内容:

 const results = useQueries([
   {
     queryKey: ["post", 1],
     queryFn: useData2("barQuery", "BAR_TEST_SINGLE", setBarData),
   },
   {
     queryKey: ["post", 2],
     queryFn: useData2("lineQuery", "LINE_TEST", setLineData),
   },
 ]);

但现在我收到此错误:TypeError: _this2.options.queryFn is not a function

我的查询格式设置不正确吗?我该如何解决?或者,是否有其他方法可以在同一组件中使用 react-query 运行 不同的查询?

不,这不是 useQueries 的正确语法。您不能将 useQuery 挂钩作为 queryFn - queryFn 需要获取数据的函数,在您的情况下,这将是 fetchData(chartId, "models").

然而,您最初问题的根本原因似乎是您的情况只等到 一个 查询完成加载:

const isLoading = loadingLine && loadingBar;

如果 loadingLinefalse 并且 loadingBartrue,这种情况将产生 false,因此您将不再显示加载微调器。如果你想等到 all 查询完成加载,那就是:

const isLoading = loadingLine || loadingBar;

最后,我想指出,没有必要将数据从 react-query 复制到本地状态。 react-query 将 return 来自 queryFn 的结果 return 作为 data 字段。我的实现看起来像这样:

export function useData(queryId, chartId) {
  return useQuery(
    [queryId, chartId],
    () => fetchData(chartId, "models")
  );
}

const { error: errorBar, isLoading: loadingBar, data: barData } = useData(
    "barQuery",
    "BAR_TEST_SINGLE",
  );
  const { error: errorLine, isLoading: loadingLine, data: lineData } = useData(
    "lineQuery",
    "LINE_TEST",
  );

  const isLoading = loadingLine || loadingBar;

或者 useQueries:

 const results = useQueries([
   {
     queryKey: ["barQuery", "BAR_TEST_SINGLE"],
     queryFn: () => fetchData("BAR_TEST_SINGLE", "models")
   },
   {
     queryKey: ["lineQuery", "LINE_TEST"],
     queryFn: () => fetchData("LINE_TEST", "models")
   },
 ]);

const isLoading = results.some(result => result.isLoading)

我无法添加评论,因为我的声誉目前太低了,但我遇到了与 vaibhav-deep 相同的问题,所以我想我会把它放在这里,即使它有点 off-topic .

通过返回 async/await 获取函数中的任何数据修复了此问题。

const queries = useQueries(
queryList.map((query) => {
  return {
    queryKey: [query],
    queryFn: () => fetchData(query),
  };
})
);

async function fetchData(query) {
  const response = await axios.get(apiCall)... 
  
  ...

  return response.data;
}

@TKDo,您的解决方案仅适用于“4.0.0-alpha.1”之前的 react-query 版本,如果我们使用任何最新版本的 react-query ( “4.0.0-alpha.2”及以上)。为了解决这个问题,我们需要使用一个对象并将查询列表作为值分配给查询键,如下例所示。

const results = useQueries({queries: [
{
  queryKey: ["barQuery", "BAR_TEST_SINGLE"],
  queryFn: () => fetchData("BAR_TEST_SINGLE", "models")
},
{
  queryKey: ["lineQuery", "LINE_TEST"],
  queryFn: () => fetchData("LINE_TEST", "models")
}]});

React-Query V4 Migration docs for reference