initial commit
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# cache-invalidation: Use Targeted Invalidation Over Broad Patterns
|
||||
|
||||
## Priority: CRITICAL
|
||||
|
||||
## Explanation
|
||||
|
||||
Query invalidation marks cached data as stale, triggering background refetches. Use targeted invalidation to refresh only affected data. Overly broad invalidation causes unnecessary network requests; too narrow invalidation leaves stale data.
|
||||
|
||||
## Bad Example
|
||||
|
||||
```tsx
|
||||
// Invalidating everything after a single todo update
|
||||
const mutation = useMutation({
|
||||
mutationFn: updateTodo,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries() // Invalidates ENTIRE cache
|
||||
},
|
||||
})
|
||||
|
||||
// Invalidating too broadly
|
||||
const mutation = useMutation({
|
||||
mutationFn: updateTodoStatus,
|
||||
onSuccess: () => {
|
||||
// Invalidates all todos including unrelated lists
|
||||
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
||||
},
|
||||
})
|
||||
|
||||
// Missing invalidation of related queries
|
||||
const mutation = useMutation({
|
||||
mutationFn: addComment,
|
||||
onSuccess: () => {
|
||||
// Only invalidates comment list, misses comment count
|
||||
queryClient.invalidateQueries({ queryKey: ['comments', postId] })
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
## Good Example
|
||||
|
||||
```tsx
|
||||
// Targeted invalidation with exact matching
|
||||
const mutation = useMutation({
|
||||
mutationFn: updateTodo,
|
||||
onSuccess: (data, variables) => {
|
||||
// Invalidate specific todo and related queries
|
||||
queryClient.invalidateQueries({ queryKey: ['todos', variables.id] })
|
||||
// Also invalidate lists that might contain this todo
|
||||
queryClient.invalidateQueries({ queryKey: ['todos', 'list'] })
|
||||
},
|
||||
})
|
||||
|
||||
// Use exact: true when you only want one specific query
|
||||
const mutation = useMutation({
|
||||
mutationFn: updateUserProfile,
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['user', 'profile'],
|
||||
exact: true, // Only this exact key, not ['user', 'profile', 'settings']
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
// Invalidate multiple related queries
|
||||
const mutation = useMutation({
|
||||
mutationFn: addComment,
|
||||
onSuccess: (data, { postId }) => {
|
||||
// Invalidate all comment-related queries for this post
|
||||
queryClient.invalidateQueries({ queryKey: ['posts', postId, 'comments'] })
|
||||
queryClient.invalidateQueries({ queryKey: ['posts', postId, 'comment-count'] })
|
||||
// Optionally invalidate the post itself if it shows comment count
|
||||
queryClient.invalidateQueries({ queryKey: ['posts', postId] })
|
||||
},
|
||||
})
|
||||
|
||||
// Predicate-based invalidation for complex scenarios
|
||||
queryClient.invalidateQueries({
|
||||
predicate: (query) =>
|
||||
query.queryKey[0] === 'todos' &&
|
||||
query.state.data?.userId === currentUserId,
|
||||
})
|
||||
```
|
||||
|
||||
## Invalidation Patterns
|
||||
|
||||
```tsx
|
||||
// Prefix matching (default) - invalidates all matching prefixes
|
||||
queryClient.invalidateQueries({ queryKey: ['todos'] })
|
||||
// Matches: ['todos'], ['todos', 1], ['todos', { status: 'done' }]
|
||||
|
||||
// Exact matching - only the exact key
|
||||
queryClient.invalidateQueries({ queryKey: ['todos'], exact: true })
|
||||
// Matches: ['todos'] only
|
||||
|
||||
// Predicate matching - custom logic
|
||||
queryClient.invalidateQueries({
|
||||
predicate: (query) => query.queryKey.includes('user-generated'),
|
||||
})
|
||||
|
||||
// Refetch type control
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['todos'],
|
||||
refetchType: 'active', // Only refetch active queries (default)
|
||||
// refetchType: 'inactive' - Only inactive
|
||||
// refetchType: 'all' - Both
|
||||
// refetchType: 'none' - Mark stale but don't refetch
|
||||
})
|
||||
```
|
||||
|
||||
## Context
|
||||
|
||||
- Invalidation only marks queries as stale; refetch happens when query is used
|
||||
- `refetchType: 'active'` (default) only refetches queries with active observers
|
||||
- Use hierarchical query keys to enable precise invalidation
|
||||
- Consider `setQueryData` for optimistic updates instead of invalidation
|
||||
- Always test invalidation patterns to ensure all affected queries are refreshed
|
||||
Reference in New Issue
Block a user