React hooks
Zodios comes with a Query and Mutation hook helper.
It's a thin wrapper around React-Query but with zodios auto completion and automatic key management.
No need to remember your keys anymore.
Zodios query hook also returns an invalidation helper to allow you to reset react query cache easily.
Zodios Hooks instance
When creating an instance or zodios hooks, you need to provide a name that will be used as react-query
key prefix and your instance of Zodios Api Client.
new ZodiosHooks(name: string, client: Zodios)
Example
const apiClient = new Zodios(baseUrl, [...]);
const apiHooks = new ZodiosHooks("myAPI", apiClient);
Zodios hooks methods
hooks.use[Alias]
You will usually want to use aliases to call your endpoints. You can define them in the alias
option in your API definition endpoint.
query alias:
Query alias hooks will return a QueryResult
object from react-query
with:
- the response data and all react-query result properties
- the generated
key
- the
invalidate
helper.
function use[Alias](config?: ZodiosRequestOptions, queryOptions: QueryOptions): QueryResult<Response>;
example:
// identical to hooks.useQuery("/users")
const { data: users, isLoading, isError, invalidate, key } = hooks.useGetUsers();
immutable query alias:
function use[Alias](body: Body, config?: ZodiosRequestOptions, queryOptions: QueryOptions): QueryResult<Response>;
example:
// identical to hooks.useImmutableQuery("/users/search")
const { data: users, isLoading, isError } = hooks.useSearchUsers({ name: "John" });
Immutable query aliases are only available for post
endpoints.
you also need to set the immutable
option to true
in your API definition endpoint if you want alias to use useImmutableQuery
hook.
mutation alias
Alias for post
, put
, patch
, delete
endpoints:
function use[Alias](config?: ZodiosRequestOptions, queryOptions?: QueryOptions): MutationResult<Response>;
example:
// identical to usePost("/users") or useMutation("post","/users")
const { mutate } = hooks.useCreateUser();
zodios.useQuery
Generic request method that allows to do queries (same as useGet).
Query hooks will return a QueryResult
object from react-query
with:
- the response data and all react-query result properties
- the generated
key
- the
invalidate
helper.
useQuery(path: string, config?: ZodiosRequestOptions, queryOptions?: QueryOptions): QueryResult<Response>;
Example:
const { data: users, isLoading, isError } = hooks.useQuery('/users');
check react-query documentation for more informations on QueryResult
and QueryOptions
.
zodios.useImmutableQuery
Generic request method that allows to do queries on post requests.
useImmutableQuery(path: string, body: Body ,config?: ZodiosRequestOptions, queryOptions?: QueryOptions): QueryResult<Response>;
Example:
const { data: users, isLoading, isError } = hooks.useImmutableQuery('/users/search', { name: "John" });
check react-query documentation for more informations on QueryResult
and QueryOptions
.
zodios.useInfiniteQuery
Generic request method that allows to load pages indefinitly.
useInfiniteQuery(path: string, config?: ZodiosRequestOptions, infiniteQueryOptions?: InfiniteQueryOptions): InfiniteQueryResult<Response>;
Compared to native react-query infinite query, you also need to provide a function named getPageParamList
to tell zodios which parameters will be used to paginate. Indeed, zodios needs to know it to be able to generate the correct query key automatically for you.
Example:
const { data: userPages, isFectching, fetchNextPage } = apiHooks.useInfiniteQuery(
"/users",
{
// request 10 users per page
queries: { limit: 10 },
},
{
// tell zodios to not use page as query key to allow infinite loading
getPageParamList: () => ["page"],
// get next page param has to return the next page as a query or path param
getNextPageParam: (lastPage, pages) => lastPage.nextPage ? {
queries: {
page: lastPage.nextPage,
},
}: undefined;
}
);
check react-query infinite query documentation for more informations on InfiniteQueryResult
and InfiniteQueryOptions
.
zodios.useImmutableInfiniteQuery
Generic request method that allows to search pages indefinitly with post requests.
useImmutableInfiniteQuery(path: string, body: Body ,config?: ZodiosRequestOptions, infiniteQueryOptions?: InfiniteQueryOptions): InfiniteQueryResult<Response>;
Compared to native react-query infinite query, you also need to provide a function named getPageParamList
to tell zodios which parameters will be used to paginate. Indeed, zodios needs to know it to be able to generate the correct query key automatically for you.
Example:
const { data: userPages, isFectching, fetchNextPage } = apiHooks.useImmutableInfiniteQuery(
"/users/search",
{
// search for users named John
name: "John",
// request 10 users per page
limit: 10,
},
undefined,
{
// tell zodios to not use page as query key to allow infinite loading
getPageParamList: () => ["page"],
// get next page param has to return the next page as a query or path param
getNextPageParam: (lastPage, pages) => lastPage.nextPage ? {
body: {
page: lastPage.nextPage,
},
}: undefined;
}
);
check react-query infinite query documentation for more informations on InfiniteQueryResult
and InfiniteQueryOptions
.
zodios.useMutation
Generic request method that allows to do mutations.
useMutation(method: string, path: string, config: ZodiosRequestOptions, reactQueryOptions?: ReactQueryOptions): ReactMutationResult<Response>;
Example:
const { mutate } = hooks.useMutation('post','/users');
check react-query documentation for more informations on MutationResult
and MutationOptions
.
zodios.useGet
Query hooks will return a QueryResult
object from react-query
with:
- the response data and all react-query result properties
- the generated
key
- the
invalidate
helper.
useGet(path: string, config?: ZodiosRequestOptions, reactQueryOptions?: ReactQueryOptions): ReactQueryResult<Response>;
Example:
const { data: user, isLoading, isError, invalidate, key } = hooks.useGet("/users/:id", { params: { id: 1 } });
zodios.usePost
usePost(path: string, config?: ZodiosRequestOptions, reactQueryOptions?: ReactQueryOptions): ReactMutationResult<Response>;
Example:
const { mutate } = hooks.usePost("/users");
zodios.usePut
usePut(path: string, config?: ZodiosRequestOptions, reactQueryOptions?: ReactQueryOptions): ReactMutationResult<Response>;
Example:
const { mutate } = hooks.usePut("/users/:id", { params: { id: 1 } });
zodios.usePatch
usePatch(path: string, config?: ZodiosRequestOptions, reactQueryOptions?: ReactQueryOptions): ReactMutationResult<Response>;
Example:
const { mutate } = hooks.usePatch("/users/:id", {params: {id: 1}});
zodios.useDelete
useDelete(path: string, config?: ZodiosRequestOptions, reactQueryOptions?: ReactQueryOptions): ReactMutationResult<Response>;
Example:
const { mutate } = hooks.useDelete("/users/:id", { params: {id: 1 }});
Zodios key helpers
Zodios provides some helpers to generate query keys to be used to invalidate cache or to get it directly from cache with 'QueryClient.getQueryData(key)'.
zodios.getKeyByPath
getKeyByPath(method: string, path: string, config?: ZodiosRequestOptions): QueryKey;
Examples:
To get a key for a path endpoint with parameters:
const key = zodios.getKeyByPath('get', '/users/:id', { params: { id: 1 } });
const user = queryClient.getQueryData<User>(key);
To get a key to invalidate a path endpoint for all possible parameters:
const key = zodios.getKeyByPath('get', '/users/:id');
queryClient.invalidateQueries(key);
zodios.getKeyByAlias
getKeyByAlias(alias: string, config?: ZodiosRequestOptions): QueryKey;
Examples:
To get a key for an alias endpoint with parameters:
const key = zodios.getKeyByAlias('getUser', { params: { id: 1 } });
const user = queryClient.getQueryData<User>(key);
To get a key to invalidate an alias endpoint for all possible parameters:
const key = zodios.getKeyByAlias('getUser');
queryClient.invalidateQueries(key);
Bundling
If you are bundling your App with Webpack and with a custom library that embeds @zodios/react
or @tanstack/react-query
, you need to bundle you library with both esm
and cjs
support.
We recommend using tsup to bundle your library and declare your package.json
like this
Else, you'll get the following error:
Example
import React from "react";
import { Zodios } from "@zodios/core";
import { ZodiosHooks } from "@zodios/react";
import { z } from "zod";
const baseUrl = "https://jsonplaceholder.typicode.com";
const zodios = new Zodios(baseUrl, [...]);
const zodiosHooks = new ZodiosHooks("jsonplaceholder", zodios);
const Users = () => {
const {
data: users,
isLoading,
error,
invalidate: invalidateUsers, // zodios also provides invalidation helpers
key // zodios also returns the generated key
} = zodiosHooks.useQuery("/users"); // or useGetUsers();
const { mutate } = zodiosHooks.useMutation("post", "/users", undefined, {
onSuccess: () => invalidateUsers(),
}); // or .useCreateUser(...);
return (
<>
<h1>Users</h1>
<button onClick={() => mutate({ name: "john doe" })}>add user</button>
{isLoading && <div>Loading...</div>}
{error && <div>Error: {(error as Error).message}</div>}
{users && (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)}
</>
);
};
import { QueryClient, QueryClientProvider } from "react-query";
import { Users } from "./users";
const queryClient = new QueryClient();
export const App = () => {
return (
<QueryClientProvider client={queryClient}>
<Users />
</QueryClientProvider>
);
};