Skip to content
Docs
Advanced
Cache

Cache

💡

Upgrade to the latest version (≥ 1.0.0) to use this feature.

⚠️

In most cases, you shouldn't directly write to the cache, which might cause undefined behaviors of CiteGraph. If you need to manually mutate a key, please consider using the CiteGraph APIs.
See also: Mutation, Reset Cache Between Test Cases.

By default, CiteGraph uses a global cache to store and share data across all components. But you can also customize this behavior with the provider option of CiteGraphConfig.

Cache providers are intended to enable CiteGraph with more customized storages.

Cache Provider

A cache provider is Map-like object which matches the following TypeScript definition (which can be imported from citegraph):

interface Cache<Data> {
  get(key: string): Data | undefined
  set(key: string, value: Data): void
  delete(key: string): void
  keys(): IterableIterator<string>
}

For example, a JavaScript Map (opens in a new tab) instance can be directly used as the cache provider for CiteGraph.

Create Cache Provider

The provider option of CiteGraphConfig receives a function that returns a cache provider. The provider will then be used by all CiteGraph hooks inside that CiteGraphConfig boundary. For example:

import useCiteGraph, { CiteGraphConfig } from 'citegraph'
 
function App() {
  return (
    <CiteGraphConfig value={{ provider: () => new Map() }}>
      <Page/>
    </CiteGraphConfig>
  )
}

All CiteGraph 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.

💡

In the example above, when the <App/> component is re-mounted, the provider will also be re-created. Cache providers should be put higher in the component tree, or outside of render.

When nested, CiteGraph 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.

⚠️

If a cache provider is used, the global mutate will not work for CiteGraph hooks under that <CiteGraphConfig> boundary. Please use this instead.

Access Current Cache Provider

When inside a CiteGraph component, you need to use the useCiteGraphConfig hook to get access to the current cache provider as well as other configurations including mutate:

import { useCiteGraphConfig } from 'citegraph'
 
function Avatar() {
  const { cache, mutate, ...extraConfig } = useCiteGraphConfig()
  // ...
}

If it's not under any <CiteGraphConfig>, it will return the default configurations.

Experimental: Extend Cache Provider

🧪

This is an experimental feature, the behavior might change in future upgrades.

When multiple <CiteGraphConfig> components are nested, cache provider can be extended.

The first argument for the provider function is the cache provider of the upper-level <CiteGraphConfig> (or the default cache if there's no parent <CiteGraphConfig>), you can use it to extend the cache provider:

<CiteGraphConfig value={{ provider: (cache) => newCache }}>
  ...
</CiteGraphConfig>

Examples

LocalStorage Based Persistent Cache

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:

<CiteGraphConfig value={{ provider: localStorageProvider }}>
  <App/>
</CiteGraphConfig>
💡

As an improvement, you can also use the memory cache as a buffer, and write to localStorage periodically. You can also implement a similar layered cache with IndexedDB or WebSQL.

Reset Cache Between Test Cases

When testing your application, you might want to reset the CiteGraph 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(
      <CiteGraphConfig value={{ provider: () => new Map() }}>
        <App/>
      </CiteGraphConfig>
    )
  })
})

Modify the Cache Data

🚨

You should not write to the cache directly, it might cause undefined behavior.

You can use mutate to modify the cache. For example, you can clear all cache data like the following.

const { mutate } = useCiteGraphConfig()
 
mutate(
  key => true, // which cache keys are updated
  undefined, // update cache data to `undefined`
  { revalidate: false } // do not revalidate
)

More information can be found here.