axios-hooks, react-query, and swr are libraries designed to handle data fetching and server state in React applications. axios-hooks is a specialized wrapper that binds the Axios HTTP client directly to React hooks, simplifying request execution but coupling logic to Axios. react-query (now evolved into TanStack Query) provides a powerful framework for managing asynchronous server state, offering robust caching, background updates, and mutation tools independent of the HTTP client. swr (Stale-While-Revalidate) is a lightweight React Hook library for data fetching that focuses on speed and simplicity, automatically handling caching, revalidation, and focus detection with a minimal API surface.
When building modern React applications, managing server state is one of the most common challenges. Developers often move from basic useEffect fetching to specialized libraries to handle caching, loading states, and errors. axios-hooks, react-query, and swr offer different approaches to this problem. Let's compare how they handle real-world engineering scenarios.
axios-hooks acts as a direct bridge between Axios and React.
// axios-hooks: Direct Axios binding
import useAxios from 'axios-hooks';
function UserProfile() {
const { data, loading, error } = useAxios('/api/users/1');
if (loading) return <p>Loading...</p>;
return <div>{data.name}</div>;
}
react-query treats server data as a separate state category.
// react-query: Server state management
import { useQuery } from '@tanstack/react-query';
function UserProfile() {
const { data, isLoading, error } = useQuery({
queryKey: ['user', 1],
queryFn: () => fetch('/api/users/1').then(res => res.json())
});
if (isLoading) return <p>Loading...</p>;
return <div>{data.name}</div>;
}
swr focuses on the stale-while-revalidate strategy.
// swr: Stale-while-revalidate
import useSWR from 'swr';
function UserProfile() {
const { data, error, isLoading } = useSWR('/api/users/1', fetcher);
if (isLoading) return <p>Loading...</p>;
return <div>{data.name}</div>;
}
axios-hooks caches based on request configuration.
// axios-hooks: Config-based caching
const { data } = useAxios({
url: '/api/posts',
method: 'GET'
});
// Same config returns cached result automatically
react-query uses query keys for precise cache control.
// react-query: Key-based caching
const { data } = useQuery({
queryKey: ['posts'],
queryFn: getPosts,
staleTime: 1000 * 60 * 5 // 5 minutes
});
// queryClient.invalidateQueries(['posts']) triggers refetch
swr revalidates automatically on focus or reconnect.
// swr: Auto-revalidation
const { data, mutate } = useSWR('/api/posts', fetcher);
// Automatically revalidates when window regains focus
// mutate() manually triggers revalidation
axios-hooks uses a manual trigger hook.
// axios-hooks: Manual mutation
import useAxios from 'axios-hooks';
function EditForm() {
const [{ loading }, execute] = useAxios(
{ url: '/api/users/1', method: 'PUT' },
{ manual: true }
);
return <button onClick={() => execute()}>Save</button>;
}
react-query provides a dedicated mutation hook.
// react-query: Dedicated mutation hook
import { useMutation, useQueryClient } from '@tanstack/react-query';
function EditForm() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: updateUser,
onSuccess: () => queryClient.invalidateQueries(['users'])
});
return <button onClick={() => mutation.mutate()}>Save</button>;
}
swr offers a mutation hook or helper.
useSWRMutation is available for complex cases.mutate function for basic updates.// swr: Mutation helper
import useSWRMutation from 'swr/mutation';
function EditForm() {
const { trigger } = useSWRMutation('/api/users/1', sendPutRequest);
return <button onClick={() => trigger()}>Save</button>;
}
axios-hooks is stable but niche.
// axios-hooks: Import structure
import useAxios from 'axios-hooks';
// No major namespace changes recently
react-query has migrated to TanStack.
react-query npm package is legacy (v3).@tanstack/react-query (v4/v5).// react-query: Modern import
import { useQuery } from '@tanstack/react-query';
// Old 'react-query' package is no longer recommended
swr is actively maintained by Vercel.
// swr: Standard import
import useSWR from 'swr';
// Consistent API across recent versions
While the differences are clear, all three libraries aim to simplify data fetching in React. Here are key overlaps:
// All packages use similar hook patterns
const { data, loading, error } = useLibrary(...);
useState.// Common pattern across all three
if (loading) return <Spinner />;
if (error) return <ErrorMessage />;
// All expose error objects
const { error } = useLibrary(...);
console.error(error.message);
| Feature | axios-hooks | react-query | swr |
|---|---|---|---|
| Primary Focus | Axios Wrapper | Server State Manager | Data Fetching Hook |
| HTTP Client | Axios Only | Any (Fetch, Axios, etc.) | Any (Fetch, Axios, etc.) |
| Caching | Request Config Based | Query Key Based | URL/Key Based |
| Mutations | Manual Execute | Dedicated useMutation | useSWRMutation |
| Maintenance | Stable / Niche | Active (TanStack) | Active (Vercel) |
| Learning Curve | Low | Medium | Low |
axios-hooks is like a specialized adapter 🔌 — it connects Axios directly to your UI. Use it if you are locked into Axios and want minimal setup for simple GET requests without introducing a larger library.
react-query (TanStack Query) is like a command center 🎛️ — it gives you full control over server state, caching, and synchronization. Use it for complex dashboards, enterprise apps, or when you need robust mutation handling and cache invalidation.
swr is like a streamlined dashboard 🚀 — it gets you up and running fast with smart defaults. Use it for content sites, Next.js projects, or when you want automatic revalidation without heavy configuration.
Final Thought: For most new professional projects, react-query (TanStack) or swr are the safer long-term bets due to their flexibility and active maintenance. Reserve axios-hooks for specific scenarios where Axios coupling is already a decided standard and complexity is low.
Choose swr if you prioritize simplicity and speed with a focus on the stale-while-revalidate strategy. It is perfect for projects that need automatic revalidation on focus or reconnect, lightweight implementation, and a minimal learning curve without sacrificing essential caching features.
Choose react-query (specifically the modern @tanstack/react-query version) if you need enterprise-grade features like complex caching, optimistic updates, and pagination support. It is ideal for large-scale applications where server state management is critical and you want flexibility to switch HTTP clients without refetching logic.
Choose axios-hooks if your project is already heavily invested in Axios and you need a quick way to bind requests to components without setting up a broader state management system. It is best suited for smaller applications where tight coupling to Axios is not a concern and advanced caching strategies are not required.
SWR is a React Hooks library for data fetching.
The name “SWR” is derived from stale-while-revalidate, a cache invalidation strategy popularized by HTTP RFC 5861.
SWR first returns the data from cache (stale), then sends the request (revalidate), and finally comes with the up-to-date data again.
With just one hook, you can significantly simplify the data fetching logic in your project. And it also covered in all aspects of speed, correctness, and stability to help you build better experiences:
...and a lot more.
With SWR, components will get a stream of data updates constantly and automatically. Thus, the UI will be always fast and reactive.
View full documentation and examples on swr.vercel.app.
import useSWR from 'swr'
function Profile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (isLoading) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
In this example, the React Hook useSWR accepts a key and a fetcher function.
The key is a unique identifier of the request, normally the URL of the API. And the fetcher accepts
key as its parameter and returns the data asynchronously.
useSWR also returns 3 values: data, isLoading and error. When the request (fetcher) is not yet finished,
data will be undefined and isLoading will be true. When we get a response, it sets data and error based on the result
of fetcher, isLoading to false and rerenders the component.
Note that fetcher can be any asynchronous function, you can use your favourite data-fetching
library to handle that part.
View full documentation and examples on swr.vercel.app.
This library is created by the team behind Next.js, with contributions from our community:
Thanks to Ryan Chen for providing the awesome swr npm package name!
The MIT License.