UNPKG

tanstack-query-craft

Version:

Type-safe module registry for TanStack Query with enhanced developer experience

386 lines (302 loc) β€’ 9.11 kB
# TanStack Query Craft Type-safe module registration system for TanStack Query. Manage your queries and mutations centrally, enhance developer experience with full TypeScript support. ## Features - ✨ **Full Type Safety**: Complete type support with TypeScript - 🎯 **Centralized Management**: Manage all your queries and mutations from a single place - πŸ”„ **Easy Invalidation**: Perform query invalidation operations easily - πŸ“¦ **Modular Structure**: Organize your projects in modules - πŸš€ **Enhanced DX**: Fast development with auto-completion and type inference - 🎨 **Flexible API**: Support for dynamic query keys and variables ## Installation ```bash npm install tanstack-query-craft ``` ## Basic Usage ### 1. Defining Queries and Mutations ```typescript import { defineQuery, defineMutation, defineModule, } from "tanstack-query-craft"; // Define a query const getUser = defineQuery<{ userId: string }, User>({ queryKey: (variables) => ["users", variables.userId], queryFn: async (variables) => { const response = await fetch(`/api/users/${variables.userId}`); return response.json(); }, }); // Define a mutation const createUser = defineMutation<{ name: string; email: string }, User>({ mutationKey: ["users", "create"], mutationFn: async (variables) => { const response = await fetch("/api/users", { method: "POST", body: JSON.stringify(variables), }); return response.json(); }, }); // Create and register a module export const userModule = defineModule("user", { getUser, createUser, }); ``` ### 2. TypeScript Type Definitions Define module registration types for full type support: ```typescript // types/tanstack-query-craft.d.ts import { userModule } from "../modules/user"; import { postModule } from "../modules/post"; declare module "tanstack-query-craft" { interface TanstackQueryCraftRegistry { user: typeof userModule; post: typeof postModule; } } ``` ### 3. Usage in React Components ```typescript import { useQuery, useMutation } from "@tanstack/react-query"; import { getRegisteredQuery } from "tanstack-query-craft"; function UserProfile({ userId }: { userId: string }) { // Using a query const userQuery = useQuery( getRegisteredQuery("user", "getUser", { variables: { userId }, }) ); // Using a mutation const createUserMutation = useMutation( getRegisteredQuery("user", "createUser") ); const handleCreateUser = () => { createUserMutation.mutate({ name: "John Doe", email: "john@example.com", }); }; if (userQuery.isLoading) return <div>Loading...</div>; if (userQuery.error) return <div>An error occurred!</div>; return ( <div> <h1>{userQuery.data.name}</h1> <button onClick={handleCreateUser}>Create New User</button> </div> ); } ``` ## Advanced Usage ### Query Invalidation ```typescript import { useQueryClient } from "@tanstack/react-query"; import { invalidateQueries } from "tanstack-query-craft"; function MyComponent() { const queryClient = useQueryClient(); const invalidate = invalidateQueries(queryClient); const handleUpdate = async () => { // Invalidate a single query await invalidate.invalidate("user", "getUser", { variables: { userId: "123" }, }); // Invalidate parent query (all user queries) await invalidate.invalidate("user", "getUser", { asParent: true, }); // Invalidate by prefix await invalidate.invalidateByPrefix(["users"]); // Bulk invalidation await invalidate.invalidateBulk([ { moduleName: "user", key: "getUser", options: { variables: { userId: "1" } }, }, { moduleName: "post", key: "getPosts", options: { variables: { page: 1 } }, }, ]); // Invalidate all queries await invalidate.invalidateAll(); }; return <button onClick={handleUpdate}>Update</button>; } ``` ### Dynamic Query Keys ```typescript const getPosts = defineQuery({ queryKey: (variables) => ["posts", variables.page, variables.limit], queryFn: async (variables) => { const response = await fetch( `/api/posts?page=${variables.page}&limit=${variables.limit}` ); return response.json(); }, }); ``` ### Static Query Keys ```typescript const getAllUsers = defineQuery({ queryKey: ["users", "all"], queryFn: async () => { const response = await fetch("/api/users"); return response.json(); }, }); // Usage const query = useQuery(getRegisteredQuery("user", "getAllUsers")); ``` ### Getting Module Information ```typescript import { getRegisteredModuleNames, getModuleKeys } from "tanstack-query-craft"; // Get all registered module names const moduleNames = getRegisteredModuleNames(); console.log(moduleNames); // ['user', 'post', ...] // Get all keys of a module const userKeys = getModuleKeys("user"); console.log(userKeys); // { getUser: [Function], createUser: [Function], ... } ``` ## Example Project Structure ``` src/ β”œβ”€β”€ modules/ β”‚ β”œβ”€β”€ user/ β”‚ β”‚ β”œβ”€β”€ queries.ts β”‚ β”‚ β”œβ”€β”€ mutations.ts β”‚ β”‚ └── index.ts β”‚ β”œβ”€β”€ post/ β”‚ β”‚ β”œβ”€β”€ queries.ts β”‚ β”‚ β”œβ”€β”€ mutations.ts β”‚ β”‚ └── index.ts β”‚ └── index.ts β”œβ”€β”€ types/ β”‚ └── tanstack-query-craft.d.ts └── App.tsx ``` ### modules/user/queries.ts ```typescript import { defineQuery } from "tanstack-query-craft"; import { User } from "./types"; export const getUser = defineQuery<{ userId: string }, User>({ queryKey: (variables) => ["users", variables.userId], queryFn: async (variables) => { const response = await fetch(`/api/users/${variables.userId}`); return response.json(); }, }); export const getUsers = defineQuery<{ page: number }, User[]>({ queryKey: (variables) => ["users", "list", variables.page], queryFn: async (variables) => { const response = await fetch(`/api/users?page=${variables.page}`); return response.json(); }, }); ``` ### modules/user/mutations.ts ```typescript import { defineMutation } from "tanstack-query-craft"; import { User } from "./types"; export const createUser = defineMutation<{ name: string; email: string }, User>( { mutationKey: ["users", "create"], mutationFn: async (variables) => { const response = await fetch("/api/users", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(variables), }); return response.json(); }, } ); export const updateUser = defineMutation< { userId: string; data: Partial<User> }, User >({ mutationKey: (variables) => ["users", "update", variables.userId], mutationFn: async (variables) => { const response = await fetch(`/api/users/${variables.userId}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(variables.data), }); return response.json(); }, }); ``` ### modules/user/index.ts ```typescript import { defineModule } from "tanstack-query-craft"; import * as queries from "./queries"; import * as mutations from "./mutations"; export const userModule = defineModule("user", { ...queries, ...mutations, }); ``` ## API Reference ### defineQuery Used to define a query. ```typescript defineQuery<TVariables, TData>(config: { queryKey: QueryKey | ((variables: TVariables) => QueryKey); queryFn: (variables: TVariables) => Promise<TData>; }) ``` ### defineMutation Used to define a mutation. ```typescript defineMutation<TVariables, TData>(config: { mutationKey: MutationKey | ((variables: TVariables) => MutationKey); mutationFn: (variables: TVariables) => Promise<TData>; }) ``` ### defineModule Used to define and register a module. ```typescript defineModule<TModuleName, TModule>( name: TModuleName, module: TModule ): TModule ``` ### getRegisteredQuery Used to retrieve a registered query or mutation. ```typescript getRegisteredQuery<TModuleName, TKey, TOptions>( moduleName: TModuleName, key: TKey, options?: TOptions ) ``` ### invalidateQueries Provides helper functions for query invalidation operations. ```typescript invalidateQueries(queryClient: QueryClient): { invalidate: (moduleName, key, options?) => Promise<void>; invalidateByPrefix: (prefix: QueryKey) => Promise<void>; invalidateAll: () => Promise<void>; invalidateBulk: (queries: Array<...>) => Promise<void>; queryClient: QueryClient; } ``` ### sanitizeKey Cleans undefined, null, and empty string values from query keys. ```typescript sanitizeKey(key: unknown[] | readonly unknown[]): readonly unknown[] ``` ## Requirements - TanStack Query (React Query) v5.0.0 or higher - TypeScript 5.0 or higher ## License MIT ## Contributing We welcome your contributions! Feel free to submit pull requests. ## Author [beratazgΓΌn](https://github.com/beratazgun) ## Links - [GitHub Repository](https://github.com/beratazgun/tanstack-query-craft) - [TanStack Query Documentation](https://tanstack.com/query/latest)