Skip to content

Instantly share code, notes, and snippets.

@revskill10
Created October 13, 2018 23:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save revskill10/19f596a8509d233a6aaf0d17d0e2c533 to your computer and use it in GitHub Desktop.
Save revskill10/19f596a8509d233a6aaf0d17d0e2c533 to your computer and use it in GitHub Desktop.
ApolloClient with offline support
import {ApolloClient} from 'apollo-client'
import {InMemoryCache} from 'apollo-cache-inmemory'
import {HttpLink} from 'apollo-link-http'
import {ApolloLink} from 'apollo-link'
import {persistCache} from 'apollo-cache-persist'
import {onError} from 'apollo-link-error'
import {QueueMutationLink} from './QueueMutationLink'
import {SyncOfflineMutation} from './SyncOfflineMutation'
export const setupApolloClient = async () => {
const storage = window.localStorage
const uri = `https://api.graph.cool/simple/v1/cjicrt45i0svu01337s6tl944`
const httpLink = new HttpLink({uri})
const onErrorLink = onError(({response, graphQLErrors, networkError}) => {
console.log(networkError)
console.log(graphQLErrors)
response = {errors: null}
})
const queueLink = new QueueMutationLink({storage})
const cache = new InMemoryCache()
let link = ApolloLink.from([queueLink, onErrorLink, httpLink])
const apolloClient = new ApolloClient({link, cache,})
await persistCache({
cache,
storage: window.localStorage,
})
window.addEventListener('online', () => queueLink.open({apolloClient}))
window.addEventListener('offline', () => queueLink.close())
const syncOfflineMutation = new SyncOfflineMutation({apolloClient, storage})
await syncOfflineMutation.init()
await syncOfflineMutation.sync()
return apolloClient
}
const netInfo = () => {
const eventName = navigator && navigator.onLine ? 'online' : 'offline'
window.dispatchEvent(new Event(eventName))
}
// window.addEventListener('online', updateIndicator);
// window.addEventListener('offline', updateIndicator);
// updateIndicator();
export class SyncOfflineMutation {
constructor ({apolloClient, storage} = {}) {
if (!apolloClient) throw new Error('Apollo Client instance is required when syncing data, please assign value to it')
if (!storage) throw new Error('Storage can be window.localStorage or AsyncStorage but was not set')
this.apolloClient = apolloClient
this.storage = storage
this.storeKey = '@offlineQueueKey'
this.offlineData = []
}
getOfflineData = async () => {
return this.storage.getItem(this.storeKey)
}
hasOfflineData = () => {
return !!(this.offlineData && this.offlineData.length > 0)
}
addOfflineData = (queue = []) => {
//add only if there is a value
if (queue && queue.length > 0)
this.storage.setItem(this.storeKey, JSON.stringify(queue))
}
clearOfflineData = async () => {
this.offlineData = []
return this.storage.removeItem(this.storeKey)
}
init = async () => {
let stored = await this.getOfflineData()
this.offlineData = JSON.parse(stored) || []
}
sync = async () => {
//if there is no offline data then just exit
if (!this.hasOfflineData()) return
//return as promise, but in the end clear the storage
const uncommittedOfflineMutation = []
await Promise.all(this.offlineData.map(async (item) => {
try {
await this.apolloClient.mutate(item)
}
catch (e) {
//set the errored mutation to the stash
uncommittedOfflineMutation.push(item)
}
}))
//wait before it was cleared
await this.clearOfflineData()
//then add again the uncommited storage
this.addOfflineData(uncommittedOfflineMutation)
}
}
functionReplacer = (key, value) => {
if (typeof(value) === 'function') {
return value.toString()
}
return value
}
functionReviver = (key, value) => {
if (key === '') return value
if (typeof value === 'string') {
const rfunc = /function[^\(]*\(([^\)]*)\)[^\{]*{([^\}]*)\}/,
match = value.match(rfunc)
if (match) {
const args = match[1].split(',').map(function (arg) {
return arg.replace(/\s+/, '')
})
return new Function(args, match[2])
}
}
return value
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment