apollographql / apollo-cache-persist Goto Github PK
View Code? Open in Web Editor NEW๐ Simple persistence for all Apollo Cache implementations
License: MIT License
๐ Simple persistence for all Apollo Cache implementations
License: MIT License
Hi! I am using apollo-cache-persist with TypeScript and localForage.
apollo-client-persist with TypeScript seems to be incompatible with localForage version 1.60 and on because localForage changed its signature of the setItem
method in version 1.6.0
The setItem method
signature looks as follows in apollo-client-persist:
setItem: (key: string, data: T) => Promise<void> | void;
In localForage pre 1.6.0, the setItem method
used to look like this:
setItem<T>(key: string, value: T, callback: (err: any, value: T) => void): void;
So, obviously, they were compatible. However, in localForage post 1.6.0, the setItem method
now looks like this:
setItem<T>(key: string, value: T, callback?: (err: any, value: T) => void): Promise<T>;
Which, is incompatible because apollo-client-persist expects the setItem method
to return either Promise<void>
OR void
, yet since version 1.6.0 localForage now returns Promise<T>
We as users of apollo-client-persist could be easily warned about this through the"peerDependencies"
field within the apollo-client-persist package.json
. Or, maybe apollo-client-persist
could be upgraded to also accept Promise<T>
?
On a side note, I realize this is only a problem if using TypeScript, like I am, since this would be no problem at all with JavaScript. This is actually the first time I ever find a benefit of using JavaScript over TypeScript.
In my logout
route I'm using the new client.clearStore()
instead of resetStore()
.
I'm also using window.localStorage
as apollo-cache-persist
storage.
When I call clearStore()
it set localStorage['my-storage-key']
to: {}
.
This is a problem for many things, for example for the apollo-link-state
defaults
resolvers.
In this case is it better to delete or set to empty value the localStorage
storage?
Error occurs with this code
const cache = new InMemoryCache({
dataIdFromObject: (object: any) => object.id || null,
})
persistCache({
cache,
storage: AsyncStorage,
})
const client = new ApolloClient({
link: new HttpLink({
uri: config.graphql,
}),
cache,
})
const StartApp = withApollo(Router)
class App extends Component<any> {
public render() {
return (
<ApolloProvider client={client}>
<StartApp />
</ApolloProvider>
)
}
}
export default App
Dependencies
"apollo-cache-inmemory": "^1.2.9",
"apollo-cache-persist": "^0.1.1",
"apollo-client": "^2.4.1",
"apollo-link": "^1.2.2",
"apollo-link-context": "^1.0.8",
"apollo-link-http": "^1.5.4",
"apollo-utilities": "^1.0.20",
"graphql": "^0.14.2",
"graphql-tag": "^2.9.2",
"react": "16.3.1",
"react-apollo": "^2.1.11",
"react-native": "^0.55.4",
Current findings
With Android everything works as expected.
With iOS commenting out persistCache() -function
everything works as expected.
When using apollo-cache-persist
, if a user goes offline and creates or updates some data, will those requests occur once the user comes back online? Thanks!
/label question
Hey,
It is not clear in the documentation that persistCache
is async and should be awaited.
await persistCache({
storage: window.localStorage,
cache,
});
Removing await
breaks persistence, because the first queries will resolve before the cache is persisted, and won't resolve again when it is.
Could you please confirm that this is by design (or maybe something else is causing this and I'm wrong), and tell me if I should open a PR to clarify this in the docs?
Thanks!
It would be useful to be able to use chrome extension persistence with this library. I would think this should be pretty easy because the API of chrome.storage
is the same as window.localStorage
. Is that something that could be supported?
Hi there, I'm unsure if this is due to something relating to apollo-link-state or apollo-cache-persist, but any guidance on how I can solve this issue would be greatly appreciated as I haven't found any sample apps using apollo-cache-persist and I'm really confused on how to move forward.
here's some of my code:
https://gist.github.com/lifeiscontent/b72b8777c9707093cdd9a08b79de2fa1
the currentUser resolver is using the default resolver and the token is undefined everytime I refresh.
Hi everyone,
I had a question regarding the schema versioning functionality in combination with react-native-navigation.
At the moment, I have an async function as described in the documentation:
const SCHEMA_VERSION = '1';
const SCHEMA_VERSION_KEY = 'apollo-schema-version';
const setupClient = async () => {
// server endpoint
const uri = Platform.OS === 'ios' ? 'http://localhost:4000' : 'http://10.0.2.2:4000';
const httpLink = createHttpLink({
uri,
});
// authentication
const authMiddleware = setContext(async () => {
const token = await AsyncStorage.getItem('token');
return {
headers: {
Authorization: token ? `Bearer ${token}` : '',
},
};
});
const httpLinkWithAuth = concat(authMiddleware, httpLink);
// cache
const cache = new InMemoryCache({
addTypename: true,
});
const persistor = new CachePersistor({
cache,
storage: AsyncStorage,
});
const currentVersion = await AsyncStorage.getItem(SCHEMA_VERSION_KEY);
if (currentVersion === SCHEMA_VERSION) {
// If the current version matches the latest version,
// we're good to go and can restore the cache.
await persistor.restore();
} else {
// Otherwise, we'll want to purge the outdated persisted cache
// and mark ourselves as having updated to the latest version.
await persistor.purge();
await AsyncStorage.setItem(SCHEMA_VERSION_KEY, SCHEMA_VERSION);
}
// local state
const stateLink = withClientState({ resolvers, cache, defaults });
return new ApolloClient({
link: ApolloLink.from([stateLink, httpLinkWithAuth]),
cache,
});
};
However, when working with react-native-navigation I also need to have an HOC that is used to wrap all the separate screens I declare, like so:
export const withProvider = (Component: React.ComponentType) => {
const WrappedComponent = (props: object) => (
<ApolloProvider client={client}>
<Component {...props} />
</ApolloProvider>
);
return WrappedComponent;
};
As you can see, it needs the client in there as well.
So my question is, what is the best way to add the client to the HOC. When doing it synchronously, it didn't pose problems but now that I have a asynchronous function, I'm not sure what I should do.
I could change the code in the HOC to have an asynchronous componentWillMount, where it waits for the client. But I'm not sure if that is optimal since it will do that for all screens while the client needs to be setup asynchronously only once.
Are there any other solutions I am missing here?
Thanks a lot!
const cache = new InMemoryCache()
const client = new ApolloClient({
uri: "http://192.168.0.106:4000",
cache,
defaultOptions
})
persistCache({
cache: client.cache, // Try adding cache like this.
storage: AsyncStorage,
trigger:'write',
debug: true,
});
when we add
persistCache({
cache,
storage: AsyncStorage,
trigger:'write',
debug: true,
})
There are 2 cache instances. The client.cache is different from persistCache.
I have no idea why it works this way.
I added apollo-cache-persist
to a todo app, but it does not show persisted data when the app starts. The thing is that I checked the apollo dev tools and the data got persisted and restored correctly, but it does not get reflected in the UI. The restored data does get reflected in the UI after I update the app (add a todo).
Here is the repo, and here is a codesandbox with the todo app.
Is there something wrong about how I configured apollo-cache-persist
? Here is the commit which added it, I used persistCache
.
persistCache({
cache,
storage: window ? window.localStorage : global.localStorage
});
So checking the localstorage state I noticed that there are no timestamps or cache-control information in the cache at all. It seems like apollo-client cache is not aware of this information and is not properly invalidating data based on how old it is.
I also noticed that even if I set fetchPolicy="no-cache"
in Query
the component will still render with the cached data before making the request and showing the new data. It is arguable if this is good behaviour or not, but I believe if the data is stale it should not be shown.
This is not that big of an issue for InMemoryCache as it is cleared when you reload the page, but if you persist the cache is completely breaks the page for users after a period.
So i have the following function to setup my Apollo Client
export async function createClient() {
const cache = new InMemoryCache()
// @ts-ignore
await persistCache({
cache,
storage: AsyncStorage,
debug: true
})
const bearerLink = setContext((_, { headers, cache }) => {
const {
AuthState: { token }
} = cache.readQuery({ query: getToken })
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : ''
}
}
})
const resolvers = merge(AuthResolver, UserResolver)
const defaults = { AuthState, UserState }
const stateLink = withClientState({
cache,
resolvers,
defaults
})
return new ApolloClient({
link: ApolloLink.from([
stateLink,
bearerLink,
new HttpLink({
uri:
'https://oqegglk3l4.execute-api.us-east-1.amazonaws.com/dev/graphql'
})
]),
cache
})
}
And the following bootstrap file
export default class App extends React.Component<{}, { ready: boolean }> {
client: any
constructor() {
// @ts-ignore
super()
this.state = {
ready: false
}
}
async componentDidMount() {
this.client = await createClient()
this.setState({ ready: true })
}
render() {
const { ready } = this.state
return ready ? (
<ApolloProvider client={this.client}>
<BuddiesNavigation />
</ApolloProvider>
) : null
}
}
But for some reason the promise this.client = await createClient()
never gets resolved, and the app get's stuck.
I'm using Android.
I am getting an error when using typescript that says the localStorage type is not compatible. I have searched the issues and found #17 but that seems to be unrelated as far as I can tell.
here is what I am doing
const persistor = new CachePersistor({
cache,
storage: window.localStorage,
debug: true,
});
and here is the error I am getting
Argument of type '{ cache: InMemoryCache; storage: Storage; debug: true; }' is not assignable to parameter of type 'ApolloPersistOptions<NormalizedCacheObject>'. Types of property 'storage' are incompatible. Type 'Storage' is not assignable to type 'PersistentStorage<PersistedData<NormalizedCacheObject>>'. Types of property 'setItem' are incompatible. Type '(key: string, value: string) => void' is not assignable to type '(key: string, data: PersistedData<NormalizedCacheObject>) => void | Promise<void>'. Types of parameters 'value' and 'data' are incompatible. Type 'PersistedData<NormalizedCacheObject>' is not assignable to type 'string'. Type 'null' is not assignable to type 'string'.
Hi folks, I use apollo-cache-persist
on a mobile app and I'm looking for a solution to get data if it exists, from the cache, else get it from remote.
I am aware of apollo cache policy but the cache-first
value is not really a good solution for me.
I have a simple product list, when I click on a row, the detail screen is displayed and a product request is fired, so the request result is stored is the cache.
Then, I go back to the detail list.
Imagine 5mn later, I update my back office to change the product price.
If i go back to my detail screen, the product data will never be updated if I use the cache-first
policy and will be always updated if I use the cache-and-network
policy
Is there a way to add a cache expiration, maybe in minutes or hours ?
Hi guys I wanted to talk a bit about https://github.com/apollographql/apollo-cache-persist#how-do-i-wait-for-the-cache-to-be-restored-before-rendering-my-app as this seems to be a common problem.
The solution looks straight forward, but not very elegant. I was thinking that we could use a "render props component" in the style of the new <Query />
and <Mutation />
components to make this more elegant. In fact, I've created such a component for my own needs - https://github.com/ovotech/async-reactor-ts though its a bit more generic than that.
I was thinking that I could write a PR with something like this but more specific to apollo, so it has a nicer interface, but don't know where such a component will go, since apollo-cache-persist
does not know about React.
Issue: Typescript types check fails when using localstorage as storage for persistCache using the following example:
const cache = new InMemoryCache();
persistCache({
cache,
storage: localStorage
});
error:
[ts]
Argument of type '{ cache: InMemoryCache; storage: Storage; }' is not assignable to parameter of type 'ApolloPersistOptions<NormalizedCacheObject>'.
Types of property 'storage' are incompatible.
Type 'Storage' is not assignable to type 'PersistentStorage<PersistedData<NormalizedCacheObject>>'.
Types of property 'getItem' are incompatible.
Type '(key: string) => string | null' is not assignable to type '(key: string) => Promise<PersistedData<NormalizedCacheObject>>'.
Type 'string | null' is not assignable to type 'Promise<PersistedData<NormalizedCacheObject>>'.
Type 'null' is not assignable to type 'Promise<PersistedData<NormalizedCacheObject>>'.
var localStorage: Storage
Typescript version: 2.6.2
tsconfig.json file inclues "lib": ["esnext", "dom"],
EDIT: Typescript fails because localStorage functions don't return Promises, while the PersistentStorage type functions return Promises.
Hello,
I am pretty new to the GraphQL/Apollo thingy in general and I am having issues with the caching of the result of a query I am making.
The query takes a datetime as an argument and returns a bunch of statistics - whatever.
When the result is stored in the localStorage it looks like that: $ROOT_QUERY.statistics({"datetime":"2018-09-25T04:22:49.635Z"}):...
As you can see it is stored with the argument in the key which makes it creates a new one everytime I do a page refresh.
In the end I get something like this and my local storage quickly hits the limit.
It feels like there are multiple ways of going around this, but I wanted to understand the best practices and why it stored the arguments in the quey. Why not just leave it at $ROOT_QUERY.statistics
? What are the proper ways of handling these kind of behaviours? Not sure if this is a common issue or something very specific here.
Thanks and cheers ๐
Hi all, first thanks for your watching.
I have some issues when use "apollo-cache-persist", hope someone can help.
const cache = new InMemoryCache({...});
persistCache({
cache,
storage: AsyncStorage,
});
const client = new ApolloClient({
cache,
...
});
By default, apollo auto persist and restore my data when i query, but in console, it just show
[apollo-cache-persist] No stored cache to restore
many times although my query is success.
const cache = new InMemoryCache({...})
) is the problem, I log this cache and its data always empty although my query is success. Is this variable cache is empty, so CachePersistor can't persist my data?As far as I understand, we purge the cache once it reaches a certain size. Is there possibly a more intelligent way to do this? E.g. trim older queries, or is that impossible?
I try to use NgForage as a storage engine in Anguar 5
import { NgForage, NgForageModule} from ngforage/ngforage-ng5;
But I get a Typescript incompatible type error - any hints how to fix this?
How do I use it.
I want to use client.readQuery after the cache has been restored. Is there a way subscribe to the restore promise?
Hi, I'm having this exception Setting the value of 'apollo-cache-persist' exceeded the quota
and I already set maxSize
to false
for unlimited cache size but still getting this exception.
By the way I'm using localStorage
This is my cache persistor Object:
const persistor = new CachePersistor({
cache,
storage: window.localStorage,
debug: true,
maxSize: false
});
Just a best practice question I suppose. Is it possible to access the CachePersistor from anywhere lower down in a component tree, via a mechanism like ApolloProvider? Or is there some other neat way? Would be cool for when doing manual persist triggering. I've just used context for now.
This is probably an obvious question, but I wanted to get clarification on caching in apollo and if it is scoped to the apollo-client instance it's passed to. So if one was to have multiple apollo-clients and wanted to use CachePersistor to purge the cache, it would only purge the cache for the particular cache it is scoped too, right? I just want to make sure that calling purge on one in-memory-cache only purges that particular instance's cache in the browser.
Following code produces a TypeScript error:
import localForage from 'localforage';
import { persistCache } from 'apollo-cache-persist';
import { InMemoryCache } from 'apollo-cache-inmemory';
const cache = new InMemoryCache();
persistCache({
cache,
storage: localForage,
});
src/shared/apollo.ts:10:14 - error TS2345: Argument of type '{ cache: InMemoryCache; storage: LocalForage; }' is not assignable to parameter of type'ApolloPersistOptions<NormalizedCacheObject>'.
Types of property 'storage' are incompatible.
Type 'LocalForage' is not assignable to type 'PersistentStorage<PersistedData<NormalizedCacheObject>>'.
Types of property 'setItem' are incompatible.
Type '<T>(key: string, value: T, callback?: ((err: any, value: T) => void) | undefined) => Promise<T>' is not assignable to type '(key: string, data: PersistedData<NormalizedCacheObject>) => void | Promise<void>'.
Type 'Promise<PersistedData<NormalizedCacheObject>>' is not assignable to type 'void | Promise<void>'.
Type 'Promise<PersistedData<NormalizedCacheObject>>' is not assignable to type 'Promise<void>'.
Type 'PersistedData<NormalizedCacheObject>' is not assignable to type 'void'.
Type 'null' is not assignable to type 'void'.
10 persistCache({
~
11 cache,
~~~~~~~~
12 storage: localForage,
~~~~~~~~~~~~~~~~~~~~~~~
13 });
~
Following is my code:
import React from "react"
import ReactDOM from "react-dom"
import ApolloClient, { gql } from 'apollo-boost'
import { ApolloProvider, graphql } from 'react-apollo'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { persistCache } from 'apollo-cache-persist'
const q = gql`
query {
dog(breed: "bulldog") {
id
breed
displayImage
}
}
`
const Main = graphql(q)(({data: { loading, error, dog }})=>{
if (loading) return <p>Loading</p>
if (error) return <p>Error</p>
return <p><img alt="" src={dog.displayImage} /></p>
})
const cache = new InMemoryCache()
persistCache({
cache,
storage: window.localStorage,
debug: true,
}).then(() => {
const client = new ApolloClient({
uri: 'https://nx9zvp49q7.lp.gql.zone/graphql',
cache
})
const App = () => (
<ApolloProvider client={client}><Main /></ApolloProvider>
)
ReactDOM.render(<App />, document.getElementById("root"))
})
But I don't see anything in the localStorage in my browser (Chrome), am missing something?
I'm having an issue where on my Home screen, I download a list of for example beers i.e.
{ id, beerName, beerPrice, beerRating etc }
[online]
Now when I click on the particular item it links to the page containing the data.
[offline]
If I click on a new item that I haven't previously visited then it causes the application to crash. Whereas links I've previously visited aren't causing it to crash. So it seems it is only caching the routes I visit.
Issue Labels
I'm trying to figure out how to use this with Angular/Ionic but can't seem to get it to work:
this.apollo.create({
link: handleError.concat(auth).concat(link),
cache: persistCache({
cache: new InMemoryCache(),
storage: localStorage,
}),
});
Argument of type '{ link: ApolloLink; cache: Promise<void>; }' is not assignable to parameter of type 'ApolloClientOptions<{}>'.
Types of property 'cache' are incompatible.
Type 'Promise<void>' is not assignable to type 'ApolloCache<{}>'.
Property 'read' is missing in type 'Promise<void>'.
Would also be nice if I could use Storage
from @ionic/storage
as the storage provider.
When using fetchMore for pagination as explained in
https://www.apollographql.com/docs/react/recipes/pagination.html#fetch-more
Only the first results (those not obtained through fetchMore) are persisted. Additional results from fetchMore are not persisted
One thing I would love to implement before we ship this officially is a cache filtering mechanism. I was talking about this with James and he suggested using graphql-anywhere
to filter down the extracted store. What do you think?
Does that make any sense? When I set the CachePersitor to "Write", i seem to get a persist right before the cache is restored.
import merge from "lodash.merge";
import localstate from "./localstate";
import { AsyncStorage, ActivityIndicator, View } from "react-native";
import React, { Component } from "react";
import { ApolloClient } from "apollo-client";
import { ApolloProvider } from "react-apollo";
import { ApolloLink } from "apollo-link";
import { HttpLink } from "apollo-link-http";
import { onError } from "apollo-link-error";
import { InMemoryCache } from "apollo-cache-inmemory";
import { CachePersistor } from "apollo-cache-persist";
import { withClientState } from "apollo-link-state";
import Config from "react-native-config";
const SCHEMA_VERSION = "4"; // Must be a string.
const SCHEMA_VERSION_KEY = "apollo-schema-version";
const cache = new InMemoryCache();
const persistor = new CachePersistor({
cache,
storage: AsyncStorage,
debug: true,
trigger: "write"
});
const stateLink = withClientState({ ...merge(localstate), cache });
const httpLink = new HttpLink({
uri: Config.GRAPHQL_URL
});
const link = ApolloLink.from([stateLink, httpLink]);
class Apollo extends Component {
state = {
client: new ApolloClient({
link,
cache
}),
cacheRestored: false
};
async componentWillMount() {
try {
const currentVersion = await AsyncStorage.getItem(SCHEMA_VERSION_KEY);
if (currentVersion === SCHEMA_VERSION) {
// If the current version matches the latest version,
// we're good to go and can restore the cache.
console.log(`about to restore`);
await persistor.restore();
console.log(`cache restored`);
this.setState({ cacheRestored: true });
} else {
// Otherwise, we'll want to purge the outdated persisted cache
// and mark ourselves as having updated to the latest version.
throw `Incorrect local cache schema version`;
}
} catch (error) {
await persistor.purge();
await AsyncStorage.setItem(SCHEMA_VERSION_KEY, SCHEMA_VERSION);
this.setState({ cacheRestored: true });
}
}
render() {
return this.state.cacheRestored == true ? (
<ApolloProvider client={this.state.client} {...this.props} />
) : (
<View
style={{
flex: 1,
justifyContent: "center",
alignItems: "center"
}}
>
<ActivityIndicator />
</View>
);
}
}
export default Apollo;
The console log produces this:
about to restore
[apollo-cache-persist] Persisted cache of size 58
[apollo-cache-persist] Restored cache of size 58
cache restored
Let me know if I should dig in a bit further. I guess a restore is a "write" in a way, I set the debouce high ~3000 to make sure the restore is completed before the triggered write. With standard debounce, sometimes the write would execute first and wipe the cache.
It would be cool if restore didn't trigger a write however.
Hey!
I've just added this package to my project and it works great. I want to set it up to work this way but I don't know if it's possible:
Is this possible right now? I didn't see any option in the readme.
Thanks!
Udpate : see directly the next comment.
We can use the page visibility API to trigger background persistence on web when the tab is minimized ๐
[ts]File'../../tsconfig.base' does not exit
tsconfig.json file
"extends": "../../tsconfig.base",
"compilerOptions": {
"rootDir": "./src",
"outDir": "lib",
"lib": ["es6", "dom", "es2017.object"]
},
"include": ["src/**/*.ts"],
"exclude": ["src/**/__tests__/*.ts"]
}
my app is using
` "apollo-cache-inmemory": "^1.1.5",
"apollo-cache-persist": "^0.1.1",
"apollo-client": "^2.2.0",
"apollo-link-http": "^1.3.2",
"graphql": "^0.12.3",
"graphql-tag": "^2.6.1",
"normalize.css": "^7.0.0",
"react": "^16.2.0",
"react-apollo": "^2.0.4",
"react-dom": "^16.2.0",
"react-markdown": "^3.1.4",
"react-router-dom": "^4.2.2",
"react-scripts": "1.1.0",
"react-tooltip": "^3.4.0",
"styled-components": "^2.4.0",
"webfontloader": "^1.6.28"`
and my index.js which is the only file I've changed since I've added 'apollo-cache-persist' is
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { ApolloProvider } from 'react-apollo';
import { persistCache } from 'apollo-cache-persist';
import App from './App';
const GRAPHCMS_API = 'https://api.graphcms.com/simple/v1/poop';
const client = new ApolloClient({
link: new HttpLink({ uri: GRAPHCMS_API }),
cache: new InMemoryCache()
});
persistCache({
cache: client.cache,
storage: window.localStorage
})
ReactDOM.render(
<BrowserRouter>
<ApolloProvider client={ client } >
<App />
</ApolloProvider>
</BrowserRouter>
, document.getElementById('root'));
` ``
Hi there! I need to control my cache by saving something in secure storage (https://www.npmjs.com/package/redux-persist-sensitive-storage), something in AsyncStorage (react-native). How can I control it?
I first check the cache, then write to the cache, then check the cache again. The first time I check the cache I expect null, then after I expect 'abc'. When I close and reopen the app I expect the first cache check to be hydrated showing 'abc', but again I get null again.
import React from 'react';
import { AsyncStorage, ActivityIndicator, StyleSheet, Text, View } from 'react-native';
import { ApolloProvider, Mutation, Query, withApollo } from "react-apollo";
import ApolloClient from "apollo-boost";
import gql from "graphql-tag";
import { persistCache } from 'apollo-cache-persist';
import { InMemoryCache } from 'apollo-cache-inmemory';
const cache = new InMemoryCache();
persistCache({
cache,
storage: AsyncStorage,
});
const defaults = {
currentUser: null
}
const typeDefs = `
type Query {
currentUser: String
}
`;
const client = new ApolloClient({
cache,
uri: "...",
clientState: {
defaults,
typeDefs
}
});
const GET_USER = gql`
{
currentUser @client
}
`;
client.query({query: GET_USER}).then((data)=>{
console.log("before: ", data);
});
client.writeData({data: {currentUser: "abc"}});
client.query({query: GET_USER}).then((data)=>{
console.log("after: ", data);
});
The default max cache size is 1MB. Is there a reason for this? Will performance of apollo client drop off when the cache gets arbitrarily bigger?
Hi,
it seems from sources that on client.resetStore()
we end up with cache.reset()
so our patched method of cache.write()
is probably not triggering.
If there is no observed query active, there will not be write operation and simple browser refresh would restore cache from storage for previous user even when we directly asked to invalidate it.
And I would probably consider handling it same way even in 'background' trigger.
Hey there having an issue with apollo-boost and react native regarding local state. If i set local state for geo points and using react navigation I transition to another page the geo points are then set back to the defaults?
If i dont set defaults they dont reset but I get yellow box errors. Any ideas?
This library solves that issue, but do I need to use this library to solve it?
Can there be an option for persistCache
to work synchronously? For users that are using localStorage or sessionStorage, it would be nice to run persistCache
to completion before instantiating the client, and export the client as a direct value, instead of a Promise.
I've observed the following behavior with the following setup in my react native app...
persistCache({
cache,
storage: AsyncStorage,
trigger: 'background',
});
NOTE: I'm pretty sure I tried both backgrounding the app and not backgrounding the app.
I tracked this down to the persistCache function. When I commented it out, everything worked great. I'm not sure where user A's data is being rehydrated from because I explicitly delete the 'apollo-persist-cache' key from localstorage. if I trigger on 'write' everything works as expected as well, so that's how I've left things for now, realizing it may be a performance problem. So far, I've not noticed any performance issue though.
I ran into this edge case when working on a dynamic component builder, this is just a rough preview of it's functionality. As you select fields that you would like on the component, the GraphQL query and resulting data from the database update to reflect your selections.
I noticed when selecting the ID (_id) field when the item is already cached without the _id field selected, the cache breaks and throws errors for that particular item. It seems like the cache will store an item differently if the actual data has the _id property within the selection set.
I could see this causing an issue for normal users if two queries use the same _id variable, but on one route includes the _id property in the selection set, and a query on another route doesn't. I'm probably going to use a custom cache persister, but wanted to let you know about this anyway.
Here is a YouTube video link for clarity. The issue is visible about 20 secs in, when the _id field is added in.
Here's a link to part of the source code. Apologies, but can't release a full working version
Here is a copy of the error:
Store error: the application attempted to write an object with no provided id but the store already contains an id of BackupMonitor:5a3c5721ae08b284c4de251b for this object. The selectionSet that was trying to be written is:
BackupMonitor(_id: "5a3c5721ae08b284c4de251b") {
PlanName
CompanyName
UserName
UserID
tenant_id
__typename
} could not be cloned.
at ApolloClient.hookLogger [as devToolsHookCb] (<anonymous>:14:14)
at QueryManager.onBroadcast (http://localhost:3000/static/js/bundle.js:2526:27)
at QueryManager../node_modules/apollo-client/core/QueryManager.js.QueryManager.broadcastQueries (http://localhost:3000/static/js/bundle.js:3612:14)
at Object.next (http://localhost:3000/static/js/bundle.js:3652:31)
at SubscriptionObserver.next (http://localhost:3000/static/js/bundle.js:117881:14)
at http://localhost:3000/static/js/bundle.js:5682:76
at Array.forEach (<anonymous>)
at Object.next (http://localhost:3000/static/js/bundle.js:5682:43)
at SubscriptionObserver.next (http://localhost:3000/static/js/bundle.js:117881:14)
at Object.next (http://localhost:3000/static/js/bundle.js:6987:34)
at SubscriptionObserver.next (http://localhost:3000/static/js/bundle.js:117881:14)
at http://localhost:3000/static/js/bundle.js:8558:81
at retry (http://localhost:3000/static/js/bundle.js:8554:17)
at Object.next (http://localhost:3000/static/js/bundle.js:8558:21)
at SubscriptionObserver.next (http://localhost:3000/static/js/bundle.js:117881:14)
at http://localhost:3000/static/js/bundle.js:8406:26
at <anonymous>
VM48:17 DOMException: Failed to execute 'postMessage' on 'Window': Error: Error writing result to store for query:
{
BackupMonitor(_id: "5a3c5721ae08b284c4de251b") {
PlanName
CompanyName
UserName
UserID
tenant_id
__typename
}
}
In my opinion, queries with cache policy set to 'network-only' oughtn't to be persistent.
CachePersistor seems not to respect this policy and store all the queries.
Hi,
would not be better to stop mutating cache object and just return the wrapped version?
Current API is kinda triggering people practising functional programming.
I'd like to completely clear the cache (stored in localStorage) after a user logs out but I can't find anything in the apollo docs.
resetStore() seems to re activate all active queries, effectively restoring the data.
I've been playing around a little getting this to work with Nextjs and localStorage
, specifically with the with-apollo example, with no luck.
The gist seems to be that the example initialises apollo twice. First on the server, and subsequently on the client, with the initial state set on the server. On the server, however localStorage
is not available, hence I initialized on the client only, which seems to be the issue (localStorage
is written to, but not rehydrated from):
import { InMemoryCache } from 'apollo-cache-inmemory';
import { persistCache } from 'apollo-cache-persist';
const cache = new InMemoryCache({...});
if (process.browser) {
persistCache({
cache,
storage: window.localStorage,
});
}
The question is, will this potentially never work in an universal app like NextJS, and what would be the alternatives? The README mentions that redux-persist-cookie-storage (which seems to cater for universal apps) could be used interchangeably, but I've had no luck using that either.
Hi,
I'm trying to use apollo-cache-persist with the react and this is giving an error:
import React from 'react'
import ReactDOM from 'react-dom'
import { ApolloClient } from 'apollo-client'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloProvider } from 'react-apollo'
import { persistCache } from 'apollo-cache-persist'
import './index.css'
import App from './App'
import registerServiceWorker from './registerServiceWorker'
const cache = new InMemoryCache({...})
const client = new ApolloClient({
link: new HttpLink({
uri: '',
credentials: ''
}),
cache: cache
})
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>
, document.getElementById('root'))
registerServiceWorker()
I'm using create-react-app
Hi! ^ Hope I did that right. I'm using web, so I'll use web terminology/concepts and hope it translates.
I'm considering using this to persist some data. However, I'd like to keep separate caches to keep the data separate. I'm not sure if this is a great architectural idea overall, but it's striking me as clean at the moment. I also might want to keep stuff in local storage that isn't from apollo cache. In order to persist it, I think the library will need to basically namespace it as separate keys in storage. Is this library capable of doing such a thing? And, if so, how?
Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.