

Also from Kynth Studios


Also from Kynth Studios


Also from Kynth Studios
123456# Guidelines for Mutation Hooks78## Purpose and Overview9Mutation hooks abstract data modification operations (create, update, delete) using TanStack Query's useMutation hook. They provide loading states, error handling, and optimistic updates. These hooks connect UI components to the data access layer for write operations, keeping components focused on presentation rather than data manipulation logic.1011## Structure and Organization1213### Mutation Hooks Module Structure14```15src/16├── hooks/ # Shared hooks module17│ └── query/ # Shared query hooks (includes mutations)18│ └── [entity]/19│ ├── use-create-[entity]-mutation.ts # Create operation20│ ├── use-update-[entity]-mutation.ts # Update operation21│ ├── use-delete-[entity]-mutation.ts # Delete operation22│ └── use-[specific-action]-[entity]-mutation.ts # Other specific mutations23└── features/24 └── [feature-name]/25 └── _hooks/ # Feature-specific hooks26 └── query/ # Feature-specific query hooks (includes mutations)27 └── [entity]/28 ├── use-create-[entity]-mutation.ts29 ├── use-update-[entity]-mutation.ts30 └── use-delete-[entity]-mutation.ts31```3233## Naming Conventions3435### Files36- `use-create-[entity]-mutation.ts`: For create operations37- `use-update-[entity]-mutation.ts`: For update operations38- `use-delete-[entity]-mutation.ts`: For delete operations39- `use-[specific-action]-[entity]-mutation.ts`: For other specific actions (e.g., `use-set-active-[entity]-mutation.ts`)4041### Functions42- `useCreate[Entity]Mutation`: For create operations43- `useUpdate[Entity]Mutation`: For update operations44- `useDelete[Entity]Mutation`: For delete operations45- `use[SpecificAction][Entity]Mutation`: For other specific actions4647### Types48- `UseCreate[Entity]MutationArgs`: Arguments for create mutation hook49- `UseUpdate[Entity]MutationArgs`: Arguments for update mutation hook50- `UseDelete[Entity]MutationArgs`: Arguments for delete mutation hook51- `Use[SpecificAction][Entity]MutationArgs`: Arguments for specific action mutation hook5253## Implementation Guidelines5455### Mutation Hooks56- Use TanStack Query's `useMutation` hook57- Import mutation functions directly from `@/data`58- Use TypeScript's `MutationOptions` type for args59- Spread args at the beginning to allow overriding any option60- Always get `queryClient` using `useQueryClient()`61- Handle cache invalidation in `onSuccess`62- Handle errors in `onError` with optional error alerting utility63- Call the provided callback after internal logic6465## CRUD Mutation Examples6667### 1. Create Mutation68```typescript69// use-create-[entity]-mutation.ts70import { type MutationOptions, useMutation, useQueryClient } from '@tanstack/react-query';71import { post[Entity]s, type Post[Entity]sData, type Post[Entity]sResponse } from '@/data';72import { alertApiError } from '@/utils/api-errors';7374export type UseCreate[Entity]MutationArgs = MutationOptions<75 Post[Entity]sResponse,76 Error,77 Post[Entity]sData78>;7980export function useCreate[Entity]Mutation(args: UseCreate[Entity]MutationArgs = {}) {81 const queryClient = useQueryClient();8283 return useMutation({84 ...args,85 mutationFn: post[Entity]s,86 onSuccess: async (data, variables, context) => {87 await queryClient.invalidateQueries({ queryKey: ['/[entity]s'] });88 args.onSuccess?.(data, variables, context);89 },90 onError: (error, variables, context) => {91 if (args?.onError) return args.onError(error, variables, context);92 alertApiError(error);93 },94 });95}96```9798### 2. Update Mutation99```typescript100// use-update-[entity]-mutation.ts101import { type MutationOptions, useMutation, useQueryClient } from '@tanstack/react-query';102import {103 put[Entity]sBy[Entity]Id,104 type Put[Entity]sBy[Entity]IdData,105 type Put[Entity]sBy[Entity]IdResponse,106} from '@/data';107import { alertApiError } from '@/utils/api-errors';108109export type UseUpdate[Entity]MutationArgs = MutationOptions<110 Put[Entity]sBy[Entity]IdResponse,111 Error,112 Put[Entity]sBy[Entity]IdData113>;114115export function useUpdate[Entity]Mutation(args: UseUpdate[Entity]MutationArgs = {}) {116 const queryClient = useQueryClient();117118 return useMutation({119 ...args,120 mutationFn: put[Entity]sBy[Entity]Id,121 onSuccess: async (data, variables, context) => {122 await queryClient.invalidateQueries({ queryKey: ['/[entity]s'] });123 args.onSuccess?.(data, variables, context);124 },125 onError: (error, variables, context) => {126 if (args?.onError) return args.onError(error, variables, context);127 alertApiError(error);128 },129 });130}131```132133### 3. Delete Mutation134```typescript135// use-delete-[entity]-mutation.ts136import { type MutationOptions, useMutation, useQueryClient } from '@tanstack/react-query';137import {138 delete[Entity]sBy[Entity]Id,139 type Delete[Entity]sBy[Entity]IdData,140 type Delete[Entity]sBy[Entity]IdResponse,141} from '@/data';142import { alertApiError } from '@/utils/api-errors';143144export type UseDelete[Entity]MutationArgs = MutationOptions<145 Delete[Entity]sBy[Entity]IdResponse,146 Error,147 Delete[Entity]sBy[Entity]IdData148>;149150export function useDelete[Entity]Mutation(args: UseDelete[Entity]MutationArgs = {}) {151 const queryClient = useQueryClient();152153 return useMutation({154 ...args,155 mutationFn: delete[Entity]sBy[Entity]Id,156 onSuccess: async (data, variables, context) => {157 await queryClient.invalidateQueries({ queryKey: ['/[entity]s'] });158 args.onSuccess?.(data, variables, context);159 },160 onError: (error, variables, context) => {161 if (args?.onError) return args.onError(error, variables, context);162 alertApiError(error);163 },164 });165}166```167168### Complete CRUD Mutation Folder Structure Example169```170src/hooks/query/[entity]/171├── use-create-[entity]-mutation.ts # Create172├── use-update-[entity]-mutation.ts # Update173└── use-delete-[entity]-mutation.ts # Delete174```175176## Best Practices177178### Cache Invalidation179- Implement appropriate cache invalidation in onSuccess180- Consider which queries need to be invalidated after a mutation181- Use queryClient.invalidateQueries for cache invalidation182183### Error Handling184- Implement appropriate error handling strategies185- Forward errors to the consuming components186- Consider global error handling for common error scenarios187188### Side Effects189- Keep side effects (like showing toast notifications) in the component using the mutation190- Use the onSuccess and onError callbacks for side effects191192### Mutation States193- Expose and use mutation states (isLoading, isError, isSuccess) in UI components194- Handle different states appropriately in the UI
One repository carrying more than one format is the comparison this product exists for: does anyone actually write different content in each file, or is one a copy of the other?
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| constROD/template-react-vite.cursor/rules/data-access-via-api.mdc · 15 | Cursor rules | teststylearchtypes+1 | 74/100 | 14 days ago | |
| constROD/template-react-vite.cursor/rules/design-system.mdc · 15 | Cursor rules | lint-formatstylearchui | 58/100 | 14 days ago | |
| constROD/template-react-vite.cursor/rules/project-structure.mdc · 15 | Cursor rules | stylearchdependencies | 78/100 | 14 days ago | |
| constROD/template-react-vite.cursor/rules/query-hooks.mdc · 15 | Cursor rules | stylearchtypesperformance | 70/100 | 14 days ago | |
| constROD/template-react-vite.cursor/rules/service-layer.mdc · 15 | Cursor rules | stylearchtypes | 66/100 | 14 days ago | |
| constROD/template-react-vite.cursor/rules/styling.mdc · 15 | Cursor rules | archui | 58/100 | 14 days ago | |
| constROD/template-react-vite.cursor/rules/zustand-store.mdc · 15 | Cursor rules | teststylearchtypes+1 | 74/100 | 14 days ago | |
| constROD/template-react-viteAGENTS.md · 15 | AGENTS.md | testlint-formatstylearch+3 | 90/100 | 14 days ago | |
| constROD/template-react-viteCLAUDE.md · 15 | CLAUDE.md | testlint-formatstylearch+3 | 90/100 | 14 days ago |
Same format, overlapping stack, ranked by quality.
| Repository | Format | Stack | Covers | Score | Changed |
|---|---|---|---|---|---|
| hiromaily/go-crypto-wallet.cursor/rules/typescript.mdc · 126 | Cursor rules | setupbuildtestlint-format+6 | 100/100 | 14 days ago | |
| TechSquidTV/Hermes.cursor/rules/10-hermes-api.mdc · 46 | Cursor rules | testlint-formatstylearch+5 | 100/100 | 14 days ago | |
| dodgecfr/combatfilms-webapp.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| deifos/clipmira-subtitles.cursor/rules/frontend.mdc · 1 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| markstev/mark-starter.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+6 | 99/100 | 14 days ago | |
| Allymahmoud/case-intake-platform.cursor/rules/frontend.mdc · 0 | Cursor rules | setuptestlint-formatstyle+7 | 99/100 | 14 days ago | |
| langflow-ai/langflow.cursor/rules/docs_development.mdc · 153k | Cursor rules | setupbuildtestlint-format+7 | 97/100 | 14 days ago | |
| bybren-llc/safe-agentic-workflow.cursor/rules/10-backend-python.mdc · 399 | Cursor rules | testlint-formatstylegit+4 | 97/100 | today |
A badge carrying the measured quality of the strongest agent config file in this repository, out of 100. It reads from this index every time somebody loads your page, so it changes when the measurement changes and there is nothing to keep up to date. Free, no account, and the value is not something you or we can set by hand.
[](https://rulestack.kynth.studio/configs/constrod-template-react-vite-cursor-rules-mutation-hooks)Would rather not hotlink us? Every badge is also served in shields.io’s endpoint schema, so shields renders the image and your readers never talk to our domain:
Published by Toolproof, the masthead over this index and eight others. The method behind the number is at toolproof.kynth.studio/methodology, and the whole thing is readable as JSON with no key at /api.