axios-hooks vs react-query vs swr vs use-http
React Data Fetching Libraries Comparison
axios-hooksreact-queryswruse-httpSimilar Packages:

React Data Fetching Libraries Comparison

axios-hooks, react-query, swr, and use-http are all React libraries designed to simplify data fetching, caching, and state management for asynchronous operations. react-query (now @tanstack/react-query) and swr are the industry leaders, offering robust caching, background refetching, and mutation tools. axios-hooks is a specialized wrapper that ties fetching logic directly to the Axios HTTP client. use-http provides a lightweight, Promise-based hook for basic GET, POST, and other HTTP methods with built-in loading and error states. While all solve the problem of server state management, they differ significantly in architecture, maintenance status, and feature depth.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
axios-hooks01,89747.1 kB6a year agoMIT
react-query049,4392.26 MB1783 years agoMIT
swr032,381310 kB1953 months agoMIT
use-http02,303224 kB913 years agoMIT

React Data Fetching: axios-hooks vs react-query vs swr vs use-http

Managing server state in React applications requires more than just useEffect and fetch. The libraries axios-hooks, react-query, swr, and use-http all aim to solve this, but they take different approaches to caching, configuration, and maintenance. Let's look at how they handle real-world engineering challenges.

šŸ—ļø Architecture and Maintenance Status

react-query has evolved into @tanstack/react-query. The original react-query package on npm is considered legacy.

  • It is a standalone query client that works with any HTTP client.
  • Active development continues under the TanStack organization.
// react-query (Legacy package name, modern usage requires TanStack)
import { useQuery } from '@tanstack/react-query';

function Profile() {
  const { data } = useQuery(['user'], fetchUser);
  return <div>{data.name}</div>;
}

swr is maintained by Vercel.

  • It is a React hook library that uses a fetcher function.
  • Highly active and stable, often used with Next.js.
// swr
import useSWR from 'swr';

function Profile() {
  const { data } = useSWR('/api/user', fetcher);
  return <div>{data.name}</div>;
}

axios-hooks is a wrapper specifically for Axios.

  • Maintenance is slower compared to TanStack or Vercel projects.
  • Tightly coupled to Axios instances.
// axios-hooks
import { useAxios } from 'axios-hooks';

function Profile() {
  const [{ data, loading, error }] = useAxios('/api/user');
  return <div>{data?.name}</div>;
}

use-http is a lightweight community package.

  • Less active maintenance; suitable for simple use cases.
  • Does not require a provider wrapper at the root.
// use-http
import { useGet } from 'use-http';

function Profile() {
  const { data, loading, error } = useGet('/api/user');
  return <div>{data?.name}</div>;
}

šŸ”„ Caching and Revalidation

Caching is where these libraries differ the most. react-query and swr have sophisticated cache layers. axios-hooks and use-http are more basic.

react-query caches by query key.

  • You define stale time and cache time explicitly.
  • Automatic background refetching when data is stale.
// react-query
useQuery({
  queryKey: ['todos'],
  queryFn: fetchTodos,
  staleTime: 1000 * 60, // 1 minute
});

swr caches by URL or key.

  • Revalidates on focus by default.
  • Uses a dedupingInterval to prevent duplicate requests.
// swr
useSWR('/api/todos', fetcher, {
  dedupingInterval: 2000,
  revalidateOnFocus: true,
});

axios-hooks caches based on request configuration.

  • Caching is optional and configured via the useAxios options.
  • Less granular control over stale time compared to TanStack.
// axios-hooks
useAxios('/api/todos', {
  cache: {
    interpretHeader: true,
    methods: ['get'],
  },
});

use-http has minimal built-in caching.

  • Primarily focuses on request state rather than long-term cache management.
  • You often manage persistence manually or via context.
// use-http
// No direct cache config in hook options
const { response, get } = useGet('/api/todos');
// Caching logic usually handled outside or via custom hooks

āœļø Mutations and Data Updates

Updating data (POST, PUT, DELETE) requires handling loading states and cache invalidation.

react-query uses useMutation.

  • Provides callbacks for success, error, and settling.
  • Can automatically invalidate queries to refresh data.
// react-query
const mutation = useMutation({
  mutationFn: postTodo,
  onSuccess: () => {
    queryClient.invalidateQueries(['todos']);
  },
});

swr uses mutate.

  • You can update the local cache directly or revalidate.
  • Functional updates allow optimistic UI.
// swr
const { mutate } = useSWR('/api/todos', fetcher);

async function addTodo() {
  await mutate(createTodo(), { revalidate: true });
}

axios-hooks uses useManualAxios or standard useAxios.

  • Mutations are often treated as manual requests.
  • Cache invalidation must be triggered manually via the cache provider.
// axios-hooks
const [{ data }, execute] = useManualAxios({
  url: '/api/todos',
  method: 'post',
});

// Manually clear cache if needed

use-http provides method-specific hooks like usePost.

  • Returns a function to trigger the request.
  • Cache updates are not automatic; you rely on the response data.
// use-http
const { post, response } = usePost('/api/todos');

async function addTodo() {
  await post({ title: 'New Todo' });
}

šŸ› ļø Configuration and Setup

Setup complexity varies from zero-config to provider-heavy.

react-query requires a QueryClientProvider.

  • You must wrap your app root with the provider.
  • Allows global configuration of defaults.
// react-query
const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <HomePage />
    </QueryClientProvider>
  );
}

swr requires an SWRConfig (optional but recommended).

  • Can be used without a provider for simple cases.
  • Global config allows setting fetchers and error handlers.
// swr
function App() {
  return (
    <SWRConfig value={{ fetcher, errorRetryCount: 3 }}>
      <HomePage />
    </SWRConfig>
  );
}

axios-hooks requires an AxiosProvider.

  • You pass an Axios instance to the provider.
  • Ensures the hook uses the correct interceptors and base URL.
// axios-hooks
import { AxiosProvider } from 'axios-hooks';
import axios from 'axios';

function App() {
  return (
    <AxiosProvider axios={axios}>
      <HomePage />
    </AxiosProvider>
  );
}

use-http requires a Provider for global options.

  • Allows setting base URL and headers globally.
  • Hooks can also be used standalone without the provider.
// use-http
import { Provider } from 'use-http';

function App() {
  return (
    <Provider url='https://api.example.com'>
      <HomePage />
    </Provider>
  );
}

āš ļø Error Handling

How each library exposes errors to the component.

react-query exposes error object.

  • Includes stack trace and response data.
  • isError boolean flag for conditional rendering.
// react-query
const { error, isError } = useQuery(['user'], fetchUser);
if (isError) return <div>Error: {error.message}</div>;

swr exposes error object.

  • isValidating helps distinguish between loading and revalidating.
  • Error retries are configurable.
// swr
const { error } = useSWR('/api/user', fetcher);
if (error) return <div>Failed to load</div>;

axios-hooks exposes error in the response tuple.

  • Directly passes Axios error objects.
  • Good for accessing response status codes easily.
// axios-hooks
const [{ error }] = useAxios('/api/user');
if (error) return <div>Status: {error.response?.status}</div>;

use-http exposes error in the return object.

  • Simple boolean or error object.
  • Less detailed than Axios-specific errors unless configured.
// use-http
const { error } = useGet('/api/user');
if (error) return <div>Something went wrong</div>;

šŸ“Š Summary: Key Differences

Featurereact-queryswraxios-hooksuse-http
Maintenanceāœ… Active (TanStack)āœ… Active (Vercel)āš ļø Low Activityāš ļø Low Activity
HTTP ClientAgnosticAgnosticAxios OnlyFetch/Axios
CachingAdvancedAdvancedBasicMinimal
SetupProvider RequiredProvider OptionalProvider RequiredProvider Optional
MutationsuseMutationmutateuseManualAxiosusePost/usePut

šŸ’” The Big Picture

react-query (via TanStack) is the heavy-duty choice šŸ‹ļø. It is best for complex dashboards, enterprise apps, and teams that need strict control over caching and background sync. Note that you should install @tanstack/react-query instead of the legacy react-query package.

swr is the lightweight champion šŸƒ. It is perfect for content sites, Next.js projects, and developers who want powerful caching without the boilerplate. It feels very "React-native" in its simplicity.

axios-hooks is the Axios specialist šŸ”Œ. Use it only if you are already committed to Axios and want a quick hook wrapper without adopting a full query client. Be aware of its slower update cycle.

use-http is the simple tool šŸ”Ø. It works for small scripts, prototypes, or internal tools where setting up a query client is overkill. Do not use it for complex data synchronization needs.

Final Thought: For most professional production applications in 2024, the choice is between @tanstack/react-query and swr. The other two packages are viable for niche cases but lack the ecosystem momentum and feature depth required for large-scale architecture.

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

  • axios-hooks:

    Choose axios-hooks if your project is strictly tied to the Axios ecosystem and you need a simple wrapper without the complexity of a full caching server. It is best for smaller applications where you want Axios interceptors to work seamlessly with React hooks without configuring a separate query client.

  • react-query:

    Choose react-query (specifically the modern @tanstack/react-query version) if you need a powerful, feature-complete solution for complex server state. It is the industry standard for enterprise applications requiring advanced caching, mutations, and devtools, though you must migrate to the TanStack namespace for ongoing support.

  • swr:

    Choose swr if you prefer a lightweight, opinionated library built by Vercel that focuses on speed and simplicity. It is ideal for projects that need automatic revalidation on focus and a minimal API footprint, especially when using Next.js or Vercel infrastructure.

  • use-http:

    Choose use-http if you need a very simple, drop-in hook for basic CRUD operations without the overhead of a query client or cache configuration. It works well for small prototypes or internal tools where advanced caching strategies are unnecessary.

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