Skip to content

Use cases

Three patterns where SWR caching on resource() earns its keep.

Pain: The user switches between Orders, Invoices, and Customers. Every tab shows a spinner even when its data has not changed.

Fix: Tabs read from a shared cache. The first visit fetches; every return is immediate. Background refresh starts only when data is stale.

// Each tab is a route. Each route's store reads from a shared cache.
@Injectable() export class OrdersStore {
readonly orders = cachedResource({
cache: this.api.cache,
cacheKey: ['orders', 'list'],
loader: () => this.api.getOrders$(),
})
}
// Tab switch → store destroyed → cache survives in the API service.
// Switch back → cachedResource reads cache → instant. Background refetch
// kicks off if the entry is stale.

Pain: The user filters a list, opens a product, edits something, then navigates back. Filter state survives, but the list reloads from scratch.

Fix: Use hierarchical keys. One invalidate(['product']) after the mutation refreshes both views.

// List + detail share a key prefix. One mutation invalidates both.
cacheKey: params => ['product', 'list', params.status, params.sortBy]
cacheKey: params => ['product', 'details', params.id]
// After a mutation:
cache.invalidate(['product']) // marks BOTH list and details stale
// Background refetch on the visible view, untouched cache for the rest.

Pain: Step 2 depends on Step 1. The user goes back, changes Step 1, then returns to Step 2. The dependent fetch runs every time.

Fix: params returns undefined until ready. Once selected, the fetch runs once and caches per key. Re-selecting an earlier value is immediate.

// Step 2's params depend on Step 1's selection.
readonly categoryId = signal<string | null>(null)
readonly products = cachedResource({
cache: this.api.cache,
cacheKey: p => ['product', 'by-category', p.categoryId],
params: () => {
const id = this.categoryId()
return id ? { categoryId: id } : undefined // idle until set
},
loader: ({ params }) => this.api.getByCategory$(params.categoryId),
})
// User backs to Step 1, picks a different category → resource refetches.
// Re-picks the original category → instant from cache.