Practical Examples
QueryManager plus QueryOperations
A common production pattern is:
- create one manager for the resource
- create operations for extra action-style endpoints
- use manager
queryKeysandmutationsto coordinate cache
The action should not necessarily become its own CRUD manager.
Prefetching
function UserCard({ user }: { user: User }) {
const handleMouseEnter = () => {
// Prefetch user details when hovering
userQueryManager.prefetchRetrieve(user.id, {
staleTime: 5 * 60 * 1000
})
}
return (
<div onMouseEnter={handleMouseEnter}>
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
)
}
Custom Optimistic Update Pattern
function useOptimisticUserUpdate() {
const { mutations, queryKeys } = userQueryManager
const optimisticUpdate = async (userId: string, updates: Partial<User>) => {
// Cancel ongoing queries
await queryKeys.cancelListQueries()
// Get current data
const previousUser = queryKeys.getRetrieveData(userId)
if (!previousUser) return null
// Apply optimistic update
const optimisticUser = { ...previousUser, ...updates }
mutations.updateItems(optimisticUser)
return {
rollback: () => mutations.updateItems(previousUser),
optimisticUser
}
}
return { optimisticUpdate }
}
Action mutation beside a resource manager
const postsManager = createQueryManager<Post>({
name: 'posts',
queryClient,
// listFn, retrieveFn, createFn, updateFn, deleteFn...
})
const postOperations = createQueryOperations({ queryClient })
.mutation('favorite', async (id: number) => api.post(`/posts/${id}/favorite/`))
async function favoritePost(id: number) {
const currentPost = postsManager.queryKeys.getRetrieveData(id)
if (currentPost) {
postsManager.mutations.updateItems({
...currentPost,
is_favorite: true,
})
}
await postOperations.mutations.favorite(id)
}