Error Handling and Retry Logic with TanStack Query
Error handling and retry logic are critical features for creating robust applications that fetch data from unreliable or slow APIs. TanStack Query simplifies managing errors and retries, providing fine-grained control to handle different failure scenarios.
This tutorial will guide you through:
- Handling errors in queries and mutations.
- Configuring retry logic.
- Providing user-friendly feedback for errors.
Step 1: Setting Up TanStack Query
Install TanStack Query
npm install @tanstack/react-query
npm install @tanstack/react-query-devtools
Setup Query Client
Wrap your application with QueryClientProvider to enable query management.
App.js
import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { UsersList } from './UsersList';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<h1>Error Handling with TanStack Query</h1>
<UsersList />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
export default App;
Step 2: Basic Error Handling
TanStack Query provides an isError flag and an error object to detect and display errors.
Example: Fetching Users with Error Handling
UsersList.js
import React from 'react';
import { useQuery } from '@tanstack/react-query';
const fetchUsers = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users-invalid-endpoint');
if (!response.ok) {
throw new Error('Failed to fetch users');
}
return response.json();
};
export function UsersList() {
const { data, isLoading, isError, error } = useQuery(['users'], fetchUsers);
if (isLoading) return <p>Loading users...</p>;
if (isError) {
return <p>Error: {error.message}</p>;
}
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Explanation:
If the fetch request fails, an error is thrown, and the isError flag becomes true.
The error.message displays the reason for failure.
Step 3: Configuring Retry Logic
By default, TanStack Query retries failed queries 3 times with exponential backoff. You can customize this behavior.
Custom Retry Configuration
Use the retry and retryDelay options to define retry logic.
Example: Retry Logic
export function UsersList() {
const { data, isLoading, isError, error } = useQuery(['users'], fetchUsers, {
retry: 2, // Retry up to 2 times
retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 3000), // Exponential backoff
});
if (isLoading) return <p>Loading users...</p>;
if (isError) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Explanation:
retry: 2 limits retries to two attempts.
retryDelay defines the delay between retries using exponential backoff.
Step 4: Retry on Specific Errors
You can customize retry logic to only retry specific errors.
Example: Retry for Certain Status Codes
const fetchUsers = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users-invalid-endpoint');
if (!response.ok) {
if (response.status === 404) {
throw new Error('Not Found');
}
if (response.status >= 500) {
throw new Error('Server Error');
}
}
return response.json();
};
export function UsersList() {
const { data, isLoading, isError, error } = useQuery(['users'], fetchUsers, {
retry: (failureCount, error) => error.message === 'Server Error', // Retry only on server errors
});
if (isLoading) return <p>Loading users...</p>;
if (isError) return <p>Error: {error.message}</p>;
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Step 5: Handling Errors in Mutations
Handle errors during create, update, or delete operations with useMutation.
Example: Adding a User with Error Handling
AddUser.js
import React, { useState } from 'react';
import { useMutation } from '@tanstack/react-query';
const addUser = async (newUser) => {
const response = await fetch('https://jsonplaceholder.typicode.com/users', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newUser),
});
if (!response.ok) {
throw new Error('Failed to add user');
}
return response.json();
};
export function AddUser() {
const [name, setName] = useState('');
const mutation = useMutation(addUser, {
onError: (error) => {
alert(`Error: ${error.message}`);
},
onSuccess: () => {
alert('User added successfully!');
},
});
const handleSubmit = (e) => {
e.preventDefault();
mutation.mutate({ name });
setName('');
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter user name"
required
/>
<button type="submit" disabled={mutation.isLoading}>
{mutation.isLoading ? 'Adding...' : 'Add User'}
</button>
</form>
);
}
Step 6: Providing User Feedback
Use error states and retry counts to display meaningful feedback to users.
Example: Display Retry Count
export function UsersList() {
const { data, isLoading, isError, error, failureCount } = useQuery(['users'], fetchUsers, {
retry: 3,
});
if (isLoading) return <p>Loading users...</p>;
if (isError) {
return (
<div>
<p>Error: {error.message}</p>
<p>Retry attempts: {failureCount}</p>
</div>
);
}
return (
<ul>
{data.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Best Practices for Error Handling and Retries
Customize Retry Logic: Avoid retries for client errors (e.g., 400 status codes).
Use exponential backoff for server errors.
Graceful Error Handling: Provide clear and actionable error messages for users.
Show retry counts to inform users about ongoing attempts.
Fallback UI: Render alternative content when errors persist.
In this tutorial, you learned:
- How to handle errors in queries and mutations.
- Configuring retry logic with custom behavior.
- Providing meaningful user feedback for errors.
TanStack Query’s robust error handling and retry logic make it an excellent choice for creating resilient applications. Hope this is helpful, and I apologize if there are any inaccuracies in the information provided.
Comments
Post a Comment