Urql: Typescript bindings are missing cache.clear() on offlineExchange.

Created on 23 Jun 2020  路  5Comments  路  Source: FormidableLabs/urql

urql version & exchanges: 1.9.8
dedupExchange, offlineExchange, fetchExchange

Steps to reproduce

  1. Adding a cache.clear() update to a mutation ends with a typescript error.

image

Expected behavior

See this Pull Request for expected behaviour:
https://github.com/FormidableLabs/urql-exchange-graphcache/pull/119/files

Actual behavior

You can reproduce this error by using typescript and the offlineExchange.
This cache-type returned when using "updates" on the offlineCache has the following methods:
image

As you can see its missing the .clear() method.

I'd also like to add that the StorageAdapter type that each storage extends has the following methods in the typescript-interface:

image

But in the source code it also has the clear method as seen here:
image

Code snippet taken from this file: https://github.com/FormidableLabs/urql/blob/master/exchanges/graphcache/src/default-storage/index.ts

Most helpful comment

You'd probably want to create a custom provider for that if that's deeply used inside your app, but since the storage is also a global, you could just export it from a new file and use it directly or expose a helper function that calls storage.clear().

I tried with creating a new client, but since the store is saved in an indexeddb it doesn't get cleared.

Yes, when I'm talking about recreating the client, I'm talking about clearing the in-memory data, not the IndexedDB data, so for clearing that you'll have to call the storage.clear() method you found manually.

All 5 comments

It seems I missed in the discussion that the better approach is to recreate the cache using a wrapper where the cache is stored as state. I still think it should be possible to maybe invalidate the entire cache instead, or maybe take a new look at the .clear() method as it seems a far better solution then everyone having to write a wrapper to be able to clear the cache.

The Cache type isn鈥檛 the same as a StorageAdapter.

The cache in each function of the configuration represents the Store which implements the Cache Interface using which you can query and alter the local normalised data.

The StorageAdapter is concerned about persisting that state and restoring it on rehydration.

The default-storage has a clear() method would that persisted state can be cleared in case it becomes super stale (on a complete upgrade of the API for instance, or a log out, or a language change)

The in-memory store can鈥檛 be cleared because we don鈥檛 believe that it鈥檚 a good practice for several reasons:

  • Likely if something triggers a mutation or other action (like a logout) that switches pages the app can reinstantiate the entire urql Client which is safer as it erases more state
  • On something like a language switch, a reload may make more sense, since otherwise often local state and state outside of GraphQL isn鈥檛 erased or forgotten about, which is a rather common bug
  • We don鈥檛 want to couple the in-memory cache, which is isolated to _all_ data, which would cause all operations (queries) to reload and refetch which often also isn鈥檛 desirable

In these use-cases we鈥檝e often recommended people to simply reload or to recreate the client because it鈥檚 safer and less error-prone. This doesn鈥檛 typically prevent any use-cases, as a normalised cache that鈥檚 entirely erased doesn鈥檛 often have any other use-case where it鈥檇 be valid to erase all data and trigger a refetch, which triggers all queries on the page to refetch, while the same page and UI components to remain active.

Thanks for the answer!

How would one hook into the default-storage to clear it? Say when a user logs out. The "useClient" hook doesnt seem to give access to the clients storage. I'm thinking especially when using the offlineStorage exported by exchange-graphcache.

I tried with creating a new client, but since the store is saved in an indexeddb it doesn't get cleared. Deleting the database as well works to erase all the data, but doesn't seem to trigger the useQuery:ies to rerun.

You'd probably want to create a custom provider for that if that's deeply used inside your app, but since the storage is also a global, you could just export it from a new file and use it directly or expose a helper function that calls storage.clear().

I tried with creating a new client, but since the store is saved in an indexeddb it doesn't get cleared.

Yes, when I'm talking about recreating the client, I'm talking about clearing the in-memory data, not the IndexedDB data, so for clearing that you'll have to call the storage.clear() method you found manually.

Sounds like a good plan! Thanks!

Was this page helpful?
0 / 5 - 0 ratings