examples/swr-site/content/en/docs/advanced/cache.mdx
import { Callout } from 'nextra/components'
<Callout>Upgrade to the latest version (≥ 1.0.0) to use this feature.</Callout>
<Callout type="warning"> In most cases, you shouldn't directly _write_ to the cache, which might cause undefined behaviors of SWR. If you need to manually mutate a key, please consider using the SWR APIs.See also: Mutation, Reset Cache Between Test Cases.
</Callout>By default, SWR uses a global cache to store and share data across all
components. But you can also customize this behavior with the provider option
of SWRConfig.
Cache providers are intended to enable SWR with more customized storages.
A cache provider is Map-like object which matches the following TypeScript
definition (which can be imported from swr):
interface Cache<Data> {
get(key: string): Data | undefined
set(key: string, value: Data): void
delete(key: string): void
}
For example, a JavaScript Map instance can be directly used as the cache provider for SWR.
The provider option of SWRConfig receives a function that returns a
cache provider. The provider will then be used by all SWR
hooks inside that SWRConfig boundary. For example:
import useSWR, { SWRConfig } from 'swr'
function App() {
return (
<SWRConfig value={{ provider: () => new Map() }}>
<Page />
</SWRConfig>
)
}
All SWR hooks inside <Page> will read and write from that Map instance. You
can also use other cache provider implementations as well for your specific use
case.
import { CacheImage } from '@app/_icons'
<CacheImage className="mt-6 dark:invert" />When nested, SWR hooks will use the upper-level cache provider. If there is no
upper-level cache provider, it fallbacks to the default cache provider, which is
an empty Map.
When inside a React component, you need to use the
useSWRConfig
hook to get access to the current cache provider as well as other configurations
including mutate:
import { useSWRConfig } from 'swr'
function Avatar() {
const { cache, mutate, ...extraConfig } = useSWRConfig()
// ...
}
If it's not under any <SWRConfig>, it will return the default configurations.
When multiple <SWRConfig> components are nested, cache provider can be
extended.
The first argument for the provider function is the cache provider of the
upper-level <SWRConfig> (or the default cache if there's no parent
<SWRConfig>), you can use it to extend the cache provider:
<SWRConfig value={{ provider: cache => newCache }}>...</SWRConfig>
With the flexibility of the cache provider API, you can even build a "partial mutation" helper.
In the example below, matchMutate can receive a regex expression as key, and
be used to mutate the ones who matched this pattern.
function useMatchMutate() {
const { cache, mutate } = useSWRConfig()
return (matcher, ...args) => {
if (!(cache instanceof Map)) {
throw new Error(
'matchMutate requires the cache provider to be a Map instance'
)
}
const keys = []
for (const key of cache.keys()) {
if (matcher.test(key)) {
keys.push(key)
}
}
const mutations = keys.map(key => mutate(key, ...args))
return Promise.all(mutations)
}
}
Then inside your component:
function Button() {
const matchMutate = useMatchMutate()
return (
<button onClick={() => matchMutate(/^\/api\//)}>
Revalidate all keys start with "/api/"
</button>
)
}
You might want to sync your cache to localStorage. Here's an example
implementation:
function localStorageProvider() {
// When initializing, we restore the data from `localStorage` into a map.
const map = new Map(JSON.parse(localStorage.getItem('app-cache') || '[]'))
// Before unloading the app, we write back all the data into `localStorage`.
window.addEventListener('beforeunload', () => {
const appCache = JSON.stringify(Array.from(map.entries()))
localStorage.setItem('app-cache', appCache)
})
// We still use the map for write & read for performance.
return map
}
Then use it as a provider:
<SWRConfig value={{ provider: localStorageProvider }}>
<App />
</SWRConfig>
When testing your application, you might want to reset the SWR cache between test cases. You can simply wrap your application with an empty cache provider. Here's an example with Jest:
describe('test suite', async () => {
it('test case', async () => {
render(
<SWRConfig value={{ provider: () => new Map() }}>
<App />
</SWRConfig>
)
})
})
Alert: you should not write to the cache directly, it might cause undefined behavior.
const { cache } = useSWRConfig()
cache.get(key) // Get the current data for a key.
cache.clear() // ⚠️ Clear all the cache. SWR will revalidate upon re-render.