react-query-factory
v0.1.0
Published
Create API client for your React app with just one line of code, using React Query!
Downloads
262
Maintainers
Readme
React Query Factory Documentation
Introduction
The react-query-factory
library provides a streamlined and type-safe approach to organizing your API layer in React applications when using TanStack's React Query. By simply providing a "service" object to the createQueriesFromService
function, developers can generate a fully typesafe queries object, reducing boilerplate and enhancing code clarity and maintainability.
Getting Started
Installation
To begin using react-query-factory
, you must first ensure that @tanstack/react-query
is installed and set up in your project as it is a peer dependency. If not, you can install it using npm or yarn:
npm install @tanstack/react-query
or
yarn add @tanstack/react-query
Once React Query is installed, you can proceed to install react-query-factory
:
npm install react-query-factory
or
yarn add react-query-factory
Basic Usage
Define a Service Object: Start by defining a service object that includes methods for your API calls. Each method should return a promise resolving to the data you wish to fetch or mutate.
// Example service object const productService = { async getProducts(): Promise<Product[]> { // Implementation for fetching products }, async getProductById(id: string): Promise<Product> { // Implementation for fetching a single product by ID }, async createProduct(productData: Omit<Partial<Product>, 'id'>): Promise<Product> { // Implementation for creating a new product }, };
Generate Queries and Mutations: Use
createQueriesFromService
to generate query and mutation hooks from your service object.import { createQueriesFromService } from 'react-query-factory'; const queries = createQueriesFromService(productService, 'products');
Besides a service object
createQueriesFromService
, acceptsqueryKeyPrefix
as a second argument. This is required so we can automatically generatequeryKey
for every query.Use Generated Hooks in Components: You can now use the generated query and mutation hooks in your components.
import React from 'react'; const ProductList = () => { const { data, isLoading, error } = queries.getProducts.useQuery(); const { mutate } = queries.createProduct.useMutation(); if (isLoading) return <div>Loading...</div>; if (error) return <div>An error occurred: {error.message}</div>; return ( <ul> {data?.map(product => ( <li key={product.id}>{product.name}</li> ))} </ul> ); };
Generating Query Keys with react-query-factory
With react-query-factory
, query keys are generated automatically based on the service method names and parameters. Keys are coupled to queries itself so you don't have to manage them at all.
Default Query Keys
By default, createQueriesFromService
generates query keys using the following pattern:
[queryKeyPrefix, methodName, ...methodParams];
queryKeyPrefix
: A string you provide when generating queries and mutations, acting as a namespace for your keys.methodName
: The name of the service method used for the query or mutation.methodParams
: Parameters passed to the query or mutation, ensuring uniqueness for different parameter values.
Example: Using Query Keys
Consider a scenario where you have a query to fetch a product by its ID. The query key might be generated as follows:
const productQueryKey = queries.products.getById.queryKey({ id: '2' });
This generates a query key like ['products', 'getById', { id: '2' }]
, uniquely identifying the query within the React Query cache.
Utilizing Query Keys in Components
Query keys can be used directly in your components for various purposes, such as manually invalidating or refetching queries. Here's an example of how you might use a query key in a component:
function Index() {
const queryClient = useQueryClient();
const product = queryClient.getQueryData(queries.products.getById.queryKey({ id: '2' }));
return <div>{/* Render your product details */}</div>;
}
In this example, queries.products.getById.queryKey({ id: '2' })
generates the query key used to fetch the product details. This key can also be used for cache management tasks, such as invalidating the query to force a refetch if the product data changes.
Understanding and using query keys effectively allows you to manage and optimize the caching behavior of your queries and mutations, ensuring your application remains fast, responsive, and efficient.
Advanced Usage
Handling Parameters
For service methods that require parameters, react-query-factory
automatically generates hooks that accept these parameters and include them in the query key to ensure correct caching and invalidation. All cases are covered.
useQuery without params
If your service function doesn't accept params, you are able to pass options
to the useQuery
like normal. With the exception of queryKey
and queryFn
params.
const { data } = queries.products.getAll.useQuery();
//or
const { data } = queries.products.getAll.useQuery({
enabled: true,
refetchInterval: 6000,
...
});
useQuery with params
If your service function accepts params, you are able to pass params
and options
arguments to the useQuery
hook.
const { data } = queries.products.getById.useQuery({id: "123"});
//or
const { data } = queries.products.getById.useQuery({id: "123"}, {
enabled: true,
refetchInterval: 6000,
...
});
//or if params are optional but you still want to pass options
const { data } = queries.products.getById.useQuery(undefined, {
enabled: true,
refetchInterval: 6000,
...
});
useMutation without params
If your service function doesn't accept params, you are still able to pass options
argument:
const { mutate } = queries.products.createProduct.useMutation();
//or
const { mutate } = queries.products.createProduct.useMutation({ onSuccess: () => alert('on mutation success') });
mutate(); // doesn't require any params, no TS error
useMutation with params
If your service function accepts params, you are able to pass params
to mutate
function and options
arguments to the useMutation
hook.
const { mutate } = queries.products.createProduct.useMutation();
mutate({name: "iPhone pro", image: "xyz.com/img.jpg", ... })
mutate() // Will throw TS error
//or
const { mutate } = queries.products.createProduct.useMutation({ enabled: false, ... });
Centralized API layer
It's suggested that you have one object which encapsulates all of the queries. For example:
const postsService = { getPosts, createPosts, getPostById };
const productService = { getProducts, addProductToCard, getProductById };
const postsQueries = createQueriesFromService(postsService, "posts");
const productsQueries = createQueriesFromService(productService, "products");
const queries = { posts: postsQueries, products: productsQueries };
const Foo = () => {
const { data } = queries.products.getProducts.useQuery()
...
}
This way your API layer is centralized in queries
object, so next developer doesn’t have to second guess names like productService
, since they can rely on autocomplete to offer them suggestions by typing queries.
.
Type Safety
react-query-factory
leverages TypeScript for full type safety, ensuring that your service methods, parameters, and return types are correctly typed. This reduces runtime errors and improves the developer experience.
Contributing
Contributions to react-query-factory
are welcome. Whether it's feature requests, bug reports, or pull requests, your input helps make this library better for everyone.
License
react-query-factory
is open-source software licensed under the MIT license.