UNPKG

@wisemen/vue-core-api-utils

Version:
158 lines (113 loc) 4.99 kB
--- name: cache-management description: > Type-safe QueryClient with get/set/update/invalidate methods, predicate-based updates, cascade invalidation strategy, shared cache across components, lazy refetch patterns. type: core library: vue-core-api-utils --- # @wisemen/vue-core-api-utils — Cache Management Manually read, write, update, and invalidate the query cache using the type-safe `QueryClient` wrapper. This is useful for optimistic updates and strategically invalidating affected queries. ## Setup ```typescript import { useQueryClient } from '@/api' const queryClient = useQueryClient() // Get cached data const contact = queryClient.get(['contactDetail', { contactUuid: '123' }]) // Set cached data queryClient.set( ['contactDetail', { contactUuid: '123' }], updatedContact ) // Update cached data with a predicate (returns { rollback } for reverting) const { rollback } = queryClient.update('contactList', { by: (contact) => contact.id === '123', value: (contact) => ({ ...contact, name: 'Updated' }), }) // Invalidate queries (async — triggers refetch) await queryClient.invalidate('contactList') ``` `useQueryClient()` is a helper you create in your `@/api` module (see [getting-started](../getting-started/SKILL.md)) that wraps `new QueryClient(getTanstackQueryClient())`. ## Core Patterns ### Get cached data ```typescript const queryClient = useQueryClient() // Get specific query const contact = queryClient.get( ['contactDetail', { contactUuid: '123' }] ) // Get all queries with a key const allContacts = queryClient.get('contactList') // Get exact query only const specificQuery = queryClient.get('contactList', { isExact: true }) ``` Returns the cached data or null if not cached. The QueryClient infers entity type from your query key definition. ### Set cached data ```typescript const queryClient = useQueryClient() queryClient.set( ['contactDetail', { contactUuid: '123' }], { id: '123', name: 'John', email: 'john@email.com' } ) // For lists, set works with arrays too queryClient.set('contactList', [ { id: '123', name: 'John' }, { id: '456', name: 'Jane' }, ]) ``` `set()` replaces all cached data for that query key. ### Update cached data with predicates ```typescript const queryClient = useQueryClient() // Update a single item in a list — returns { rollback } for reverting const { rollback } = queryClient.update('contactList', { by: (contact) => contact.id === '123', // Predicate value: (contact) => ({ // Transform ...contact, name: 'Updated John' }), }) // For single entities, the predicate always matches const { rollback: rollbackDetail } = queryClient.update('contactDetail', { by: (contact) => true, value: (contact) => ({ ...contact, name: 'Updated' }), }) ``` `update()` returns `{ rollback }` — a function that reverts the cache to its previous state. Use this for optimistic updates. QueryClient knows whether the entity is an array or single item, so predicates work transparently on lists. ### Invalidate and refetch ```typescript const queryClient = useQueryClient() // Invalidate all queries with this key await queryClient.invalidate('contactList') // Invalidate specific query await queryClient.invalidate(['contactDetail', { contactUuid: '123' }]) // After invalidation, the next query interaction triggers a refetch ``` Invalidation marks cached data as stale. The next interaction (component mount, user action) triggers a refetch. ## Cache Strategy > Explicitly invalidate only the queries affected by the mutation. Let lazy refetch handle the rest when users navigate to pages needing other data. > > — Maintainer guidance When a mutation succeeds, look at what changed: - If you updated a contact, invalidate `contactDetail` and `contactList` (they both show that contact) - If you archived a conversation, invalidate `conversationList` (but maybe not `conversationDetail` unless showing the one you archived) - Don't invalidate unrelated queries — let them refetch lazily when needed ## Shared Cache Across Components Important: Multiple components using the same query key share the same cached data. This is a feature, not a bug. ```typescript // ComponentA const { result: resultA } = useQuery('userDetail', { params: { id: computed(() => 'same-id') }, queryFn: () => UserService.getById('same-id'), }) // ComponentB const { result: resultB } = useQuery('userDetail', { params: { id: computed(() => 'same-id') }, queryFn: () => UserService.getById('same-id'), }) // resultA and resultB are the SAME cached value // Mutation in B invalidates A's cache ``` Use this to your advantage: invalidate a query and all components using it refetch automatically. ## See Also - [Writing Mutations](../writing-mutations/SKILL.md) — Every mutation needs to know which queries to invalidate - [Writing Queries](../writing-queries/SKILL.md) — Understanding caching strategy informs cache management choices