Skip to content

Repository files navigation

react-query-ease

Minimal Axios + React Query helper. Create per-service clients and use client.useQuery / client.useMutation without repeating Axios boilerplate.

Claude Code Skill

Get AI-assisted setup, typed hooks, auth interceptors, and streaming — directly in your editor:

claude skills install github:dibyajyoti79/react-query-ease

Then trigger with /react-query-ease in any Claude Code session.

Install

npm install react-query-ease
npm install react @tanstack/react-query

Quick example

import { createApiClient } from "react-query-ease";

const api = createApiClient({
  baseURL: "https://api.example.com",
});

const useTodos = () => {
  const query = api.useQuery({
    url: "/todos",
    method: "GET",
    key: ["todos"],
    // All Axios config props (headers, timeout, etc.) and React Query options (staleTime, enabled, etc.) can be passed directly
  });

  return {
    todos: query.data ?? [],
    isLoadingTodos: query.isLoading,
    ...query,
  };
};

const useCreateTodo = () => {
  const mutation = api.useMutation({
    url: "/todos",
    method: "POST",
    keyToInvalidate: ["todos"],
    // All Axios config props and React Query options can be passed directly
  });

  return {
    createTodo: mutation.mutate,
    isCreatingTodo: mutation.isPending,
    ...mutation,
  };
};

// For dynamic URLs in mutations (e.g., `/todos/${id}`), use a function:
const useUpdateTodo = () => {
  const mutation = api.useMutation({
    url: (variables) => `/todos/${variables.id}`, // Dynamic URL from variables
    method: "PATCH",
    keyToInvalidate: ["todos"],
  });

  return {
    updateTodo: mutation.mutate,
    isUpdatingTodo: mutation.isPending,
    ...mutation,
  };
};

function TodoList() {
  const { todos, isLoadingTodos } = useTodos();
  const { createTodo, isCreatingTodo } = useCreateTodo();

  if (isLoadingTodos) return <p>Loading...</p>;

  return (
    <>
      <button
        disabled={isCreatingTodo}
        onClick={() => createTodo({ title: "Buy milk" })}
      >
        Add todo
      </button>
      <ul>
        {todos.map((todo) => (
          <li key={todo.id}>{todo.title}</li>
        ))}
      </ul>
    </>
  );
}

Want the full CRUD + folder structure walkthrough? Check examples/todo-crud.md. Need interceptor reference? See examples/interceptors.md. For native streaming, check the Streaming Guide.

Built-in auth interceptor helper

import { createApiClient, createAuthInterceptor } from "react-query-ease";

const tokens = {
  access: null as string | null,
  refresh: null as string | null,
};

const authInterceptor = createAuthInterceptor({
  getAccessToken: () => tokens.access,
  getRefreshToken: () => tokens.refresh,
  refreshTokens: async () => {
    const result = await fetch("/auth/refresh", {
      method: "POST",
      body: JSON.stringify({ refresh_token: tokens.refresh }),
    }).then((res) => res.json());

    tokens.access = result.accessToken;
    tokens.refresh = result.refreshToken;

    return result;
  },
});

export const secureApi = createApiClient({
  baseURL: "/api",
  configure: authInterceptor,
});

createAuthInterceptor wires up access-token headers, coalesces simultaneous refreshes, retries queued requests with the fresh token, and allows you to plug in logout/error handling via the options object.

About

An npm package that simplifies Axios and React Query integrations with reusable API clients, authentication handling, token refresh, request retries, and cache management.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages