为重新获取设置状态对象时反应查询隐藏错误消息

React query hide error message when setting state object for refetching

在 React 查询中,目前我正在调用 api,当出现错误时,它会显示错误,但是,当我更改状态对象以进行新调用时,它会显示加载数据但不隐藏错误信息?我创建了一个示例,我添加了一个会给出错误消息的按钮,即

stackblitz 示例:https://stackblitz.com/edit/react-ts-6wugxj?file=index.tsx

import React from 'react';
import { render } from 'react-dom';
import { useQuery } from 'react-query';
import axios from 'axios';
import { QueryClient, QueryClientProvider } from 'react-query';

const App: React.FunctionComponent = () => {
  const queryKey = 'getData';

  const [number, setNumber] = React.useState(1)

  const getData = async (): Promise<any> => {
    await new Promise((resolve) => setTimeout(resolve, 1000));
    const response = await axios
      .get(`https://jsonplaceholder.typicode.com/posts/${number}`)
      .then((res) => res.data);
    return response;
  };

  const {
    data: result,
    isFetching,
    status,
    error,
    refetch,
  }: any = useQuery(queryKey, getData, {
    refetchOnWindowFocus: false,
    staleTime: 0,
    cacheTime: 0,
    refetchInterval: 0,
  });

  React.useEffect(() => {
    refetch();
}, [number, refetch]);

  return (
    <div className="Container">
      <button onClick={refetch}>Refetch query</button>
      <button onClick={() => setNumber(() => 1)}>Get 1</button>
      <button onClick={() => setNumber(() => 2)}>Get 2</button>
      <button onClick={() => setNumber(() => 3)}>Get 3</button>
      <button onClick={() => setNumber(() => 99999)}>Get 99999</button>
      {status === 'error' && <div className="mt-5">{error.message}</div>}
      {isFetching ? (
        <div className="mt-5">Loading data ...</div>
      ) : (
        <div>
          {status === 'success' && (
            <div>
              {/* {result?.map((inner: any, index: number) => {
                return <li key={index}>{inner.title}</li>;
              })} */}
               <p><strong>id:</strong> {result?.id}</p>
              <p>{result?.title}</p>
            </div>
          )}
        </div>
      )}
    </div>
  );
};

const queryClient = new QueryClient();

render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>,
  document.getElementById('root')
);

我在这里看到了多种误解:

  1. a refetch 不会“清除”状态。事实上,react-query 永远不会因为你重新获取它而从活动查询中删除状态。这就是该库所建立的整个陈旧而重新验证的原则:在获取新数据时显示旧数据,然后在新数据进入后更新屏幕。这正是您的示例中发生的事情。

  2. 根本原因实际上完全不同:您使用相同的缓存键,然后在效果中强制调用 refetch。这意味着

a) 第一次获取将发生两次(一次来自 useQuery 调用,然后来自重新获取) b) 你只会缓存最新的结果,这意味着你并没有真正使用来自 react-query 的缓存。


最好的方法是将查询执行提取 所需的所有依赖项放入 查询键中。这也是in the docs here.

这样,react-query 将:

  • 当依赖项发生变化时自动触发重新获取。
  • 如果在进行后台重新获取时缓存有数据,则立即从缓存中为您提供数据。

最好的做法是将数据获取函数 (getData) 移出组件,这样它就不会意外关闭不是的东西查询键的一部分。

看起来像这样:

const App: React.FunctionComponent = () => {
  const [number, setNumber] = React.useState(1)

  const { data, status } = useQuery(['getData', number], () => getData(number));

就是这样。没有效果,没有重新获取。

此外,您提供的一些选项是默认的:staleTime 默认为 zerorefetchInterval 也默认关闭,因此您不必提供它. cacheTime of zero 只有当你想在查询被使用后立即进行垃圾收集时才需要,这通常不是你想要的,特别是因为键现在实际上正在改变,因为它们中有一个变量.

最后,您可能不想检查 isFetching 以卸载整个结果列表。 isFetching 只要有取指操作,它就永远为真,它不是状态机的一部分。使用不断变化的键,您可能想要的是仅在 status === 'loading' 时显示微调器,因为当您第一次在数字之间切换时会遇到这种硬加载状态。