重试React查询的详细指南

310 阅读2分钟

这是使用React Query与TypeScript的系列文章中的另一篇文章。

在这篇文章中,我们将探讨React Query中的重试功能,这在通过脆弱的连接获取数据时非常有用。在实现我们自己的自定义重试逻辑之前,我们首先探索默认的重试行为。

App state

我们的起点

我们将从我们在入门文章中完成的代码开始。

这就是获取函数的样子:

type Character = {
  name: string;
};
type Params = {
  queryKey: [string, { id: number }];
};
async function getCharacter(params: Params) {
  const [, { id }] = params.queryKey;
  const response = await fetch(`https://swapi.dev/api/people/${id}/`);
  if (!response.ok) {
    throw new Error("Problem fetching data");
  }
  const character = await response.json();
  assertIsCharacter(character);

  return character;
}
function assertIsCharacter(character: any): asserts character is Character {
  if (!("name" in character)) {
    throw new Error("Not character");
  }
}

这是包含查询的组件:

export function App() {
  const { status, error, data } = useQuery<Character, Error>(
    ["character", { id: 1 }],
    getCharacter
  );

  if (status === "loading") {
    return <div>...</div>;
  }
  if (status === "error") {
    return <div>{error!.message}</div>;
  }
  return data ? <h3>{data.name}</h3> : null;
}

默认的重试行为

让我们改变fetch 的调用,使资源没有被找到:

const response = await fetch(`https://swapi.dev/api/unknown/${id}/`);

读取函数现在会引发一个错误,让我们看看会发生什么:

Default try behavior

在放弃之前,获取函数最多重试三次。每次重试的延迟都会变长--1秒、2秒和4秒。

防止重试

重试行为可以用retry 选项来覆盖。要完全关闭重试,我们将retry 设置为false

const { status, error, data } = useQuery<Character, Error>(
  ["character", { id: 1 }],
  getCharacter,
  {    retry: false  });

改变重试的次数

要改变重试的次数,我们可以将retry 设置为我们需要的次数:

const { status, error, data } = useQuery<Character, Error>(
  ["character", { id: 1 }],
  getCharacter,
  {
    retry: 5  }
);

上述查询最多重试5次。

基于获取错误的重试

retry 也可以被设置为一个函数。当重试逻辑依赖于获取错误时,这很有用。

在我们尝试这个方法之前,让我们创建一个扩展了标准Error 类的类,在错误中存储HTTP状态代码:

class FetchError extends Error {
  constructor(public message: string, public statusCode: number) {
    super(message);
  }
}

我们现在可以改变获取函数来引发这种类型的错误:

async function getCharacter({
  queryKey,
}: {
  queryKey: [string, { id: number }];
}) {
  ...
  if (!response.ok) {
    throw new FetchError("Problem fetching character", response.status);  }
  ...
}

我们现在可以实现一个重试函数,如下所示:

const { status, error, data } = useQuery<Character, FetchError>(
  ["character", { id: 1 }],
  getCharacter,
  {
    retry: (failureCount, error) =>        error.statusCode === 404 && failureCount <= 3 ? true : false,  }
);

重试函数接收失败的次数和从获取函数抛出的错误对象。

重试函数预计将返回一个布尔值,表示是否应该重试。

在这个例子中,如果没有找到资源,查询最多重试3次。

改变重试延迟

重试延迟可以通过retryDelay 选项来改变:

const { status, error, data } = useQuery<Character, FetchError>(
  ["character", { id: 1 }],
  getCharacter,
  {
    retry: (failureCount, error) =>
        error.statusCode === 404 && failureCount <= 3 ? true : false,
    retryDelay: retryCount => retryCount === 0 ? 1000 : 5000  }
);

retryDelay 被设置为一个函数,它接收重试次数并返回等待下一次重试的毫秒数。

在上面的例子中,第一次重试延迟为1秒,随后的重试为5秒。

不错😊