-
Notifications
You must be signed in to change notification settings - Fork 462
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue Invalidating Storage #2443
Comments
I have the same issue as you; the DB is just.. not cleared. 👍 Same versions as you. I use a custom ClientProvider
createClient
On logout and/or before login, I tried to clear the cache, but it just stays the same. |
@leggomuhgreggo I had success in clearing IndexedDB via ... const transaction = global.indexedDB.deleteDatabase('graphql-cache');
await new Promise((resolve, reject) => {
transaction.addEventListener('success', resolve);
transaction.addEventListener('error', reject);
}); The database will be deleted. The only issue is that you have to reload the page until the browser does not have access to the data anymore (I guess it is in RAM?). Even though Chrome DevTools doesn't show a DB anymore, the data will still be retrieved from it when That is the best workaround I have found yet. |
const transaction = global.indexedDB.deleteDatabase('graphql-cache');
await new Promise((resolve, reject) => {
transaction.addEventListener('success', resolve);
transaction.addEventListener('error', reject);
});
setClient(createClientProp()); Are you doing the above? In your code example it looks like you first reconstruct the client which would mean that it still has the oppurtunity to read before it gets cleared/destroyed |
Yes, I am - but only because Here's my whole import {
createClient as urqlCreateClient,
dedupExchange,
fetchExchange,
Provider as UrqlProvider,
} from 'urql';
import { devtoolsExchange } from '@urql/devtools';
import { offlineExchange } from '@urql/exchange-graphcache';
import { makeDefaultStorage } from '@urql/exchange-graphcache/default-storage';
import { refocusExchange } from '@urql/exchange-refocus';
import { requestPolicyExchange } from '@urql/exchange-request-policy';
import schema from '../../../schema.json';
// Create a persistent cache storage
const storage = makeDefaultStorage();
/**
* Create a `urql` client
*
* @param {import('urql').ClientOptions} opts
* @return {Client}
*/
export const createClient = (opts) =>
urqlCreateClient({
url: `${config.api.urls.gateway.http}/graphql`,
exchanges: [
devtoolsExchange,
dedupExchange,
offlineExchange({
schema,
storage,
keys: {
LeadPage: () => null,
PropertyObjectDetails: () => null,
},
resolvers: {
Queries: {
lead: (data, args) => ({
__typename: 'Lead',
id: args.id,
}),
},
},
}),
fetchExchange,
refocusExchange(),
requestPolicyExchange(),
],
fetchOptions: () => {
const accessToken = getAccessToken(computeLocalBundle());
return {
headers: { authorization: accessToken ? `Bearer ${accessToken}` : '' },
};
},
...opts,
});
export const ClientContext = React.createContext({
resetClient: () => {},
client: null,
});
/**
* ClientProvider
*
* Provides `urql` client and allows resetting it via `useClient` to clear caches.
*
* @see https://github.com/FormidableLabs/urql/issues/297#issuecomment-504782794
*/
export const ClientProvider = ({
createClient: createClientProp,
children,
}) => {
const [client, setClient] = React.useState(createClientProp());
return (
<ClientContext.Provider
value={{
resetClient: async () => {
setClient(createClientProp());
await storage.clear();
// This should not be here in the best case :)
const transaction = global.indexedDB.deleteDatabase('urql-cache');
await new Promise((resolve, reject) => {
transaction.addEventListener('success', resolve);
transaction.addEventListener('error', reject);
});
},
client,
}}
>
<UrqlProvider value={client}>{children}</UrqlProvider>
</ClientContext.Provider>
);
};
ClientProvider.propTypes = {
createClient: PropTypes.func.isRequired,
children: PropTypes.element,
};
ClientProvider.defaultProps = {
children: null,
};
/**
* UseClient
*
* @example
* const { resetClient, client } = useClient();
* @return {{ resetClient, client }}
*/
export const useClient = () => React.useContext(ClientContext); So, basically what I do is before logging in and when logging out, I call... import { useClient } from 'app-lib/urql';
// Hook that runs on every login
export const useLoginFlow = () => {
const { resetClient } = useClient();
// Other stuff.
resetClient();
}
// Hook that runs on every logout
export const useLogoutFlow = () => {
const { resetClient } = useClient();
// Other stuff.
resetClient();
} I'll see if it works without re-creating the client and/or switching the order. |
I reduced It is, as far as I can see, executed properly... it just doesn't clear anything. |
Quickly forked the example to show what I mean, you are dealing with a non-awaited function there because of the iife closure. This means that you will clear when the client is activating or is still active meaning it can still read the store. Here's an example of how this can work sandbox You will see that initially the data will output an empty object, when we press login it will still log an empty object, after 1 second it will show you the hydrated state, when we press logout you will see an empty object again. |
Your example does show an empty console.log, but Check the network tab. It does load the data from cache, and Chrome shows the IndexedDB database also does not get cleared. This is a video after login: urql-cache.mp4... and this is the graphcache after logout: Is this intended behaviour? What I implemented in my project, for completeness sakeIt has the same issue as described above, though. export const ClientProvider = ({
createClient: createClientProp,
children,
}) => {
const [client, setClient] = React.useState(createClientProp());
return (
<ClientContext.Provider
value={{
storage,
createClient: async () => setClient(createClientProp()),
clearClient: async () => {
await storage.clear();
setClient(null);
const data = await storage.readData();
console.log(data);
},
client,
}}
>
<UrqlProvider value={client}>{children}</UrqlProvider>
</ClientContext.Provider>
);
}; In my login and logout flow/functions, I |
Overview
Trying to validate the Cache Invalidation on Logout functionality, extended with
storage.clear()
using graphcache + offlineExchange.Doesn't seem to want to clear as expected.
Repro: codesandbox
[email protected]
@urql/[email protected]
Things I've Tried So Far
I reviewed these related issues [#1684, #297] and looked over the relevant code but nothing jumped out at me.
My IndexedDB chops aren't very sophisticated but I took a swing at manually deleting the db with
indexedDB.deleteDatabase(dbName)
but no luck (blocked transaction I think, may revisit)Quite possible I've overlooked something simple.
Additional Context
In case it's useful, my goal is to make sure there's no chance of user PII sticking around in the browser, in case someone is using my app from a public computer, for example.
Thanks!
The text was updated successfully, but these errors were encountered: