ESLint plugin to enforce best practices when working with TanStack Query
npm install eslint-plugin-react-query-must-invalidate-queries --save-dev
# or
yarn add eslint-plugin-react-query-must-invalidate-queries --dev
# or
pnpm add eslint-plugin-react-query-must-invalidate-queries --save-dev
# or
bun add eslint-plugin-react-query-must-invalidate-queries --devAdd react-query-must-invalidate-queries to the plugins section of your .eslintrc configuration file:
{
"plugins": ["react-query-must-invalidate-queries"],
"rules": {
"react-query-must-invalidate-queries/require-mutation-invalidation": "error" // or "warn"
}
}You can see a real world config here using this: https://github.com/ayinke-llc/malak/blob/main/web/ui/eslint.config.mjs
🔧 This rule enforces that useMutation hooks include an onSuccess callback that
calls invalidateQueries to ensure data consistency.
When using mutations in React Query, it's important to invalidate related queries after a successful mutation to ensure the UI reflects the latest server state without having to do a lot of mental prep.
This rule helps prevent stale data by ensuring that mutations properly invalidate affected queries.
This rule enforces:
- Presence of an
onSuccesscallback inuseMutationhooks - The
onSuccesscallback must include a call toinvalidateQueries
✅ Examples of correct code:
useMutation({
mutationFn: updateUser,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["users"] });
},
});
useMutation({
mutationFn: updateUser,
onSuccess: () => {
const { invalidateQueries } = queryClient;
invalidateQueries({ queryKey: ["users"] });
},
});
useMutation({
mutationFn: updateUser,
onSuccess: async () => {
await someOtherOperation();
await queryClient.invalidateQueries({ queryKey: ["users"] });
},
});❌ Examples of incorrect code:
useMutation({
mutationFn: updateUser,
});
useMutation({
mutationFn: updateUser,
onSuccess: () => {
console.log("Success!");
},
});
useMutation({
mutationFn: updateUser,
onSuccess: () => {},
});You might want to disable this rule if:
- You have mutations that intentionally don't need to invalidate any queries
- You're handling cache updates through other means like
setQueryData - You have a specific caching strategy that doesn't require query invalidation
Contributions are welcome! Please read our contributing guidelines to get started.
MIT