axios-hooks vs react-query vs swr
React Data Fetching and Server State Management
axios-hooksreact-queryswrSimilar Packages:

React Data Fetching and Server State Management

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.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
axios-hooks01,90147.1 kB6a year agoMIT
react-query048,9372.26 MB1553 years agoMIT
swr032,347310 kB189a month agoMIT

React Data Fetching: axios-hooks vs React Query vs SWR

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.

🏗️ Core Philosophy: Wrapper vs. State Manager

axios-hooks acts as a direct bridge between Axios and React.

  • It wraps Axios instances into hooks.
  • Best for teams standardizing on Axios who want less boilerplate.
  • Tightly couples your components to the Axios library.
// 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.

  • It manages caching, synchronization, and updates independently.
  • Works with any HTTP client (fetch, axios, graphql).
  • Requires more setup but offers greater control.
// 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.

  • It returns cached data immediately while fetching fresh data in the background.
  • Extremely minimal configuration for basic use cases.
  • Built by Vercel with Next.js integration in mind.
// 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>;
}

🔄 Caching and Revalidation Strategies

axios-hooks caches based on request configuration.

  • Identical config objects return cached promises.
  • Less flexible for complex invalidation scenarios.
  • Manual control required for refetching.
// 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.

  • You can invalidate specific queries by key.
  • Supports background refetching on window focus.
  • Highly configurable stale times.
// 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.

  • Default behavior is to show stale data then update.
  • Simple API for manual revalidation.
  • Great for real-time feel without websockets.
// swr: Auto-revalidation
const { data, mutate } = useSWR('/api/posts', fetcher);
// Automatically revalidates when window regains focus
// mutate() manually triggers revalidation

✏️ Handling Mutations (POST/PUT/DELETE)

axios-hooks uses a manual trigger hook.

  • Separates read and write operations clearly.
  • Requires managing loading state manually.
  • Less built-in support for optimistic updates.
// 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.

  • Includes callbacks for success, error, and settlement.
  • Supports optimistic updates out of the box.
  • Integrates with query invalidation automatically.
// 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.
  • Simple mutate function for basic updates.
  • Optimistic updates require manual cache manipulation.
// swr: Mutation helper
import useSWRMutation from 'swr/mutation';

function EditForm() {
  const { trigger } = useSWRMutation('/api/users/1', sendPutRequest);
  return <button onClick={() => trigger()}>Save</button>;
}

📦 Package Status and Maintenance

axios-hooks is stable but niche.

  • Not deprecated, but development pace is slower.
  • Tied to Axios ecosystem updates.
  • Suitable for legacy Axios-heavy codebases.
// axios-hooks: Import structure
import useAxios from 'axios-hooks';
// No major namespace changes recently

react-query has migrated to TanStack.

  • The react-query npm package is legacy (v3).
  • New projects should use @tanstack/react-query (v4/v5).
  • Active maintenance with frequent updates.
// react-query: Modern import
import { useQuery } from '@tanstack/react-query';
// Old 'react-query' package is no longer recommended

swr is actively maintained by Vercel.

  • Stable API with incremental improvements.
  • Strong integration with Next.js features.
  • Regular security and performance patches.
// swr: Standard import
import useSWR from 'swr';
// Consistent API across recent versions

🌐 Similarities: Shared Ground

While the differences are clear, all three libraries aim to simplify data fetching in React. Here are key overlaps:

1. ⚛️ Hook-Based API

  • All three use React Hooks for component logic.
  • Encourage functional component patterns.
  • Manage loading and error states internally.
// All packages use similar hook patterns
const { data, loading, error } = useLibrary(...);

2. 🔄 Automatic Loading States

  • Provide boolean flags for UI feedback.
  • Reduce boilerplate compared to useState.
  • Standardize error handling across components.
// Common pattern across all three
if (loading) return <Spinner />;
if (error) return <ErrorMessage />;

3. 🛡️ Error Handling

  • Capture HTTP errors automatically.
  • Expose error objects to components.
  • Allow retry logic configuration.
// All expose error objects
const { error } = useLibrary(...);
console.error(error.message);

📊 Summary: Key Differences

Featureaxios-hooksreact-queryswr
Primary FocusAxios WrapperServer State ManagerData Fetching Hook
HTTP ClientAxios OnlyAny (Fetch, Axios, etc.)Any (Fetch, Axios, etc.)
CachingRequest Config BasedQuery Key BasedURL/Key Based
MutationsManual ExecuteDedicated useMutationuseSWRMutation
MaintenanceStable / NicheActive (TanStack)Active (Vercel)
Learning CurveLowMediumLow

💡 The Big Picture

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.

How to Choose: axios-hooks vs react-query vs swr

  • axios-hooks:

    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.

  • react-query:

    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.

  • swr:

    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.

README for axios-hooks

The license of this software has changed to AWISC - Anti War ISC license

axios-hooks

ci codecov npm version bundlephobia

React hooks for axios, with built-in support for server side rendering.

Features

  • All the axios awesomeness you are familiar with
  • Zero configuration, but configurable if needed
  • One-line usage
  • Super straightforward to use with SSR

Installation

npm install axios axios-hooks

axios is a peer dependency and needs to be installed explicitly

Version information

  • axios-hooks@5.x is compatible with axios@1.x
  • axios-hooks@4.x and below are compatible with axios@0.x

Quick Start

Edit axios-hooks Quick Start

import useAxios from 'axios-hooks'

function App() {
  const [{ data, loading, error }, refetch] = useAxios(
    'https://reqres.in/api/users?delay=1'
  )

  if (loading) return <p>Loading...</p>
  if (error) return <p>Error!</p>

  return (
    <div>
      <button onClick={refetch}>refetch</button>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  )
}

Documentation

API

Examples

Guides

API

The package exports one default export and named exports:

import useAxios, {
  configure,
  loadCache,
  serializeCache,
  makeUseAxios
} from 'axios-hooks'

useAxios(url|config, options)

The main React hook to execute HTTP requests.

  • url|config - The request URL or config object, the same argument accepted by axios.
  • options - An options object.
    • manual ( false ) - If true, the request is not executed immediately. Useful for non-GET requests that should not be executed when the component renders. Use the execute function returned when invoking the hook to execute the request manually.
    • useCache ( true ) - Allows caching to be enabled/disabled for the hook. It doesn't affect the execute function returned by the hook.
    • ssr ( true ) - Enables or disables SSR support
    • autoCancel ( true ) - Enables or disables automatic cancellation of pending requests whether it be from the automatic hook request or from the manual execute method

[!IMPORTANT]
Default caching behavior can interfere with test isolation. Read the testing section for more information.

Returns

[{ data, loading, error, response }, execute, manualCancel]

  • data - The success response data property (for convenient access).

  • loading - True if the request is in progress, otherwise False.

  • error - The error value

  • response - The whole success response object.

  • execute([config[, options]]) - A function to execute the request manually, bypassing the cache by default.

    • config - Same config object as axios, which is shallow-merged with the config object provided when invoking the hook. Useful to provide arguments to non-GET requests.
    • options - An options object.
      • useCache ( false ) - Allows caching to be enabled/disabled for this "execute" function.

    Returns

    A promise containing the response. If the request is unsuccessful, the promise rejects and the rejection must be handled manually.

  • manualCancel() - A function to cancel outstanding requests manually.

configure({ cache, axios, defaultOptions })

Allows to provide custom instances of cache and axios and to override the default options.

  • cache An instance of lru-cache, or false to disable the cache
  • axios An instance of axios
  • defaultOptions An object overriding the default Hook options. It will be merged with the default options.

serializeCache()

Dumps the request-response cache, to use in server side rendering scenarios.

Returns

Promise<Array> A serializable representation of the request-response cache ready to be used by loadCache

loadCache(cache)

Populates the cache with serialized data generated by serializeCache.

  • cache The serializable representation of the request-response cache generated by serializeCache

makeUseAxios({ cache, axios, defaultOptions })

Creates an instance of the useAxios hook configured with the supplied cache, axios instance and default options.

  • cache An instance of lru-cache, or false to disable the cache
  • axios An instance of axios
  • defaultOptions An object overriding the default Hook options. It will be merged with the default options.

Returns

An instance of useAxios React Hook which will always use the provided cache and axios instance.

The returned value, besides being a function that can be used as a React Hook, also contains the properties:

  • resetConfigure
  • configure
  • loadCache
  • serializeCache

which are the same as the package's named exports but limited to the useAxios instance returned by makeUseAxios.

Refresh Behavior

The arguments provided to useAxios(config[,options]) are watched for changes and compared using deep object comparison.

When they change, if the configuration allows a request to be fired (e.g. manual:false), any pending request is canceled and a new request is triggered, to avoid automatic cancellation you should use autoCancel:false option

Because of this, it's important to make sure that the arguments to useAxios preserve deep equality across component renders. This is often the case unless functions (e.g. axios transformers) are provided to a configuration object. In that case, those functions need to be memoized or they will trigger a request execution at each render, leading to an infinite loop.

Configuration

Unless provided via the configure function, axios-hooks uses as defaults:

  • axios - the default axios package export
  • cache - a new instance of the default lru-cache package export, with no arguments
  • defaultOptions - { manual: false, useCache: true, ssr: true, autoCancel: true }

These defaults may not suit your needs, for example:

  • you may want a common base url for axios requests
  • the default (Infinite) cache size may not be a sensible default
  • you want to disable caching altogether

In such cases you can use the configure function to provide your custom implementation of both.

When configure is used, it should be invoked once before any usages of the useAxios hook

Example

Edit axios-hooks configuration example

import { configure } from 'axios-hooks'
import LRU from 'lru-cache'
import Axios from 'axios'

const axios = Axios.create({
  baseURL: 'https://reqres.in/api'
})

const cache = new LRU({ max: 10 })

configure({ axios, cache })

Manual Requests

On the client, requests are executed when the component renders using a React useEffect hook.

This may be undesirable, as in the case of non-GET requests. By using the manual option you can skip the automatic execution of requests and use the return value of the hook to execute them manually, optionally providing configuration overrides to axios.

Example

In the example below we use the useAxios hook twice. Once to load the data when the component renders, and once to submit data updates via a PUT request configured via the manual option.

Edit axios-hooks Manual Request

import useAxios from 'axios-hooks'

function App() {
  const [{ data: getData, loading: getLoading, error: getError }] = useAxios(
    'https://reqres.in/api/users/1'
  )

  const [{ data: putData, loading: putLoading, error: putError }, executePut] =
    useAxios(
      {
        url: 'https://reqres.in/api/users/1',
        method: 'PUT'
      },
      { manual: true }
    )

  function updateData() {
    executePut({
      data: {
        ...getData,
        updatedAt: new Date().toISOString()
      }
    })
  }

  if (getLoading || putLoading) return <p>Loading...</p>
  if (getError || putError) return <p>Error!</p>

  return (
    <div>
      <button onClick={updateData}>update data</button>
      <pre>{JSON.stringify(putData || getData, null, 2)}</pre>
    </div>
  )
}

Manual Cancellation

The cancellation method can be used to cancel an outstanding request whether it be from the automatic hook request or from the manual execute method.

Example

In the example below we use the useAxios hook with its automatic and manual requests. We can call the cancellation programmatically or via controls.

function App() {
  const [pagination, setPagination] = useState({})
  const [{ data, loading }, refetch, cancelRequest] = useAxios({
    url: '/users?delay=5',
    params: { ...pagination }
  })

  const handleFetch = () => {
    setPagination({ per_page: 2, page: 2 })
  }

  const externalRefetch = async () => {
    try {
      await refetch()
    } catch (e) {
      // Handle cancellation
    }
  }

  return (
    <div>
      <button onClick={handleFetch}>refetch</button>
      <button onClick={externalRefetch}>External Refetch</button>
      <button disabled={!loading} onClick={cancelRequest}>
        Cancel Request
      </button>
      {loading && <p>...loading</p>}
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  )
}

Server Side Rendering

axios-hooks seamlessly supports server side rendering scenarios, by preloading data on the server and providing the data to the client, so that the client doesn't need to reload it.

How it works

  1. the React component tree is rendered on the server
  2. useAxios HTTP requests are executed on the server
  3. the server code awaits serializeCache() in order to obtain a serializable representation of the request-response cache
  4. the server injects a JSON-serialized version of the cache in a window global variable
  5. the client hydrates the cache from the global variable before rendering the application using loadCache

Example

Edit axios-hooks SSR example

<!-- fragment of the HTML template defining the window global variable -->

<script>
  window.__AXIOS_HOOKS_CACHE__ = {{{cache}}}
</script>
// server code for the server side rendering handler

import { serializeCache } from 'axios-hooks'

router.use(async (req, res) => {
  const index = fs.readFileSync(`${publicFolder}/index.html`, 'utf8')
  const html = ReactDOM.renderToString(<App />)

  // wait for axios-hooks HTTP requests to complete
  const cache = await serializeCache()

  res.send(
    index
      .replace('{{{html}}}', html)
      .replace('{{{cache}}}', JSON.stringify(cache).replace(/</g, '\\u003c'))
  )
})
// client side code for the application entry-point

import { loadCache } from 'axios-hooks'

loadCache(window.__AXIOS_HOOKS_CACHE__)

delete window.__AXIOS_HOOKS_CACHE__

ReactDOM.hydrate(<App />, document.getElementById('root'))

Multiple Hook Instances

Sometimes it is necessary to communicate with different APIs or use different caching strategies for different HTTP interactions.

makeUseAxios allows to create multiple instances of the useAxios React Hook which can be configured and managed independently.

In other words, makeUseAxios is a factory of useAxios, which returns a React Hook configured against the provided axios or cache instances.

This feature can also be used to create a single pre configured React Hook instance as an alternative to the global configure feature

Example

Edit axios-hooks makeUseAxios

import axios from 'axios'
import { makeUseAxios } from 'axios-hooks'

const useAxios = makeUseAxios({
  axios: axios.create({ baseURL: 'https://reqres.in/api' })
})

function App() {
  const [{ data, loading, error }, refetch] = useAxios('/users?delay=1')

  if (loading) return <p>Loading...</p>
  if (error) return <p>Error!</p>

  return (
    <div>
      <button onClick={refetch}>refetch</button>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  )
}

Testing

Testing components that make use of the useAxios hook are susceptible to test isolation leakage because of default caching behavior. The following snippets can be used to disable caching while testing:

react-testing-library

beforeAll(() => {
  useAxios.configure({ cache: false })
})

Promises

axios-hooks depends on a native ES6 Promise implementation to be supported. If your environment doesn't support ES6 Promises, you can polyfill.

Credits

axios-hooks is heavily inspired by graphql-hooks, developed by the awesome people at NearForm.

License

MIT