Retries React Query
This is another post in a series of posts using React Query with TypeScript.
Previous posts:
In this post, we will explore the retry feature in React Query which is useful when fetching data over flakey connections. We start by exploring the default retry behaviour before moving on to implementing our own custom retry logic.
Our start point
We will start from the code we finished in the Getting started post.
This is what the fetching function looks like:
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");
}
}
This is the component containing the query:
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;
}
Default retry behavior
Let’s change the fetch
call so that the resource isn’t found:
const response = await fetch(`https://swapi.dev/api/unknown/${id}/`);
The fetching function will now raise an error. Let’s see what happens:
The fetching function is retried up to three times before it gives up. The retry delay gets longer for each subsequent retry - 1 sec, 2 secs, and 4 secs.
Preventing retries
The retry behaviour can be overriden with the retry
option. To turn retries completely off we set retry
to false
:
const { status, error, data } = useQuery<Character, Error>(
["character", { id: 1 }],
getCharacter,
{ retry: false });
Changing the number of retries
To change the number of retries we can set retry
to the number we require:
const { status, error, data } = useQuery<Character, Error>(
["character", { id: 1 }],
getCharacter,
{
retry: 5 }
);
The above query is retried up to 5 times.
Retrying based on the fetching error
retry
can also be set to a function. This is useful when the retry logic is dependent on fetching error.
Before we try this out, let’s create a class that extends the standard Error
class to store the HTTP status code in the error:
class FetchError extends Error {
constructor(public message: string, public statusCode: number) {
super(message);
}
}
We can now change the fetching function to raise this type of error:
async function getCharacter({
queryKey,
}: {
queryKey: [string, { id: number }];
}) {
...
if (!response.ok) {
throw new FetchError("Problem fetching character", response.status); }
...
}
We can now implement a retry function as follows:
const { status, error, data } = useQuery<Character, FetchError>(
["character", { id: 1 }],
getCharacter,
{
retry: (failureCount, error) => error.statusCode === 404 && failureCount <= 3 ? true : false, }
);
The retry function takes in the number of failures and the error object thrown from the fetching function.
The retry function is expected to return a boolean indicating whether a retry should occur.
In this example, the query is retried up to 3 times if the resource isn’t found.
Changing the retry delay
The retry delay can be changed with the retryDelay
option.
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
is set to a function that takes in the retry count and returns the number of milliseconds to wait until the next retry.
The first retry delay is 1 second and then 5 seconds for subsequent retries in the above example.
Nice. 😊
The code in this post is available in CodeSandbox at https://codesandbox.io/s/react-query-retry-3sy9u?file=/src/App.tsx
If you to learn more about using TypeScript with React, you may find my course useful: