Skip to content

raf-query is early. The API can still change between minor releases, so use it at your own risk.

raf-query

Guides

What belongs in the cache

raf-query caches asynchronous data from a backend or the browser. What that leaves for URL state, local state and a client store.

raf-query is a cache for asynchronous data: anything you load with a promise, that can go out of date, and that many components may need. Most of that is data a backend owns — posts, users, comments. It also fits work only the browser can do: a push subscription, a notification permission, a service worker. Mark those enabled: typeof window !== "undefined" so they never run during SSR, and still use the same factories, handles, invalidation and readers as everything else.

It's not a general-purpose state manager for synchronous UI state.

Once async data lives in the cache, most apps find that what's left is small:

StateWhere it belongs
Posts, users, comments, anything from a backendraf-query
Push subscription, permission, service worker, media queryraf-query, browser-only
Filters, sort, pagination, the selected tabThe URL: search params and the path
An input's text, whether a menu is openuseState in the component
Pending and optimistic state of a writeuseActionState, useOptimistic
Theme, a draft that survives navigationA small client store, or localStorage

The URL deserves special mention. raf-query asks that anything which changes what a query fetches lives in the URL, so the loader can start the query on navigation. That's also what makes a page shareable, bookmarkable and restorable with the back button, which state in a store isn't.

Copying query data into a store

Avoid copying query data into a client store (or into useState). The copy doesn't refetch, doesn't hear about invalidation, and goes stale the moment the cache updates. Read the query wherever the data is needed: requests are deduped, and readers share one cache entry.

The exception is a form: initializing an input from query data is fine. defaultValue={post.title} gives the user their own copy to edit, and the write goes through an action.