I've been experimenting with Apollo & GraphQL. I've read that you can utilise the cache instead of requiring Vuex - but I can't wrap my head around how to do so, without creating some sort of anti-pattern of combining the two.
Has anyone got examples of how they've approached this situation?
What I'm trying:
Using Vue Apollo's CLI installation:
vue add apollo
After setting up the configurations in ./vue-apollo.js, I added an export to the provider and default options:
export const defaultOptions = {
// ...all the default settings
}
export function createProvider (options = {}) {
// Create apollo client
const { apolloClient, wsClient } = createApolloClient({
...defaultOptions,
...options,
})
apolloClient.wsClient = wsClient
// Create vue apollo provider
const apolloProvider = new VueApollo({
defaultClient: apolloClient,
defaultOptions: {
$query: {
// fetchPolicy: 'cache-and-network',
},
},
errorHandler (error) {
// eslint-disable-next-line no-console
console.log('%cError', 'background: red; color: white; padding: 2px 4px; border-radius: 3px; font-weight: bold;', error.message)
},
})
return apolloProvider
}
In ./router/index.js Import the apollo provider, options, and query...
import { createProvider, defaultOptions } from '../vue-apollo'
import gql from "graphql-tag"
import homeQuery from '@/queries/home-content.gql'
import pageQuery from '@/queries/page-query.gql'
const client = createProvider(defaultOptions).defaultClient
Function to Query the pages
const loadPage = (to, from, next) => {
return client.query({
query: pageQuery,
variables: {
slug: to.params.slug
}
})
.then(async ({ data }) => {
const { pages } = data
if (!from.name) store.commit('App/setLoadedToTrue') // Adds loader for app's first/initial load
if (pages.length > 0) {
const addPageMutation = gql`
mutation($id: ID!) {
addPage(id: $id) @client
}
`
await client.mutate({
mutation: addPageMutation,
variables: { id: pages[0].id }
})
next()
}
else next('/')
})
.catch(err => {
console.log(err)
next('/')
})
}
Function to Query the homepage content
const loadHomeData = (to, from, next) => {
const hasHomeContent = client.cache.data.data['HomePage:1']
if (hasHomeContent) next()
else {
client.query({ query: homeQuery })
.then(async () => {
if (!from.name) store.commit('App/setLoadedToTrue')
next()
})
.catch(err => {
console.log(err)
next('/error')
})
}
}
on beforeEach:
router.beforeEach((to, from, next) => {
if (!to.hash) NProgress.start()
if (to.name == 'home') return loadHomeData(to, from, next)
if (to.name == 'page') return loadPage(to, from, next)
next()
})
My Mutations & Resolvers
export const storePage = gql`
type page {
id: ID!,
title: String!,
title_highlights: String!,
image: UploadFile,
summary: String,
content_block: [ComponentPageContentBlockPageBlock]
}
type Mutation {
addPageMutation(id: ID!): page
}
`
export const storeHomePage = gql`
type homePage {
id: ID!,
bg_words: String,
title: String!,
highlights: String,
body: String,
services: [ComponentHomecontentServices],
profiles: [ComponentProfilesProfiles],
}
type Mutation {
addHomePageMutation: homePage
}
`
const resolvers = {
Mutation: {
addCaseStudyMutation: (_, ctx, { cache }) => {
const data = cache.readQuery({ query: storeCaseStudy })
cache.writeQuery({ query: storeCaseStudy, data })
return data
},
addHomePageMutation: (_, ctx, { cache }) => {
const data = cache.readQuery({ query: storeHomePage })
cache.writeQuery({ query: storeHomePage, data })
return data
}
}
}
Questions
At the moment I have two query files for each call, one for remote, one for local where it has @client against the query. Is it possible to have one query file but make it
@client
conditional based on if the data exists or not?Do we have to return the readQuery with mutations? Or could I essentially just have
addHomePageMutation: (_, ctx, { cache }) => cache.writeQuery({ query: storeHomepage })
Do we need to read the queries before mutating? And do we need to pass that data through to the writeQuery method?
The most confusing thing is, I was getting confused with storing the homepage data without passing variables, or mutating the query. In the end I just reverted it to simply just using the "Query", without the mutation, but without removing the resolvers. It still works though, the data gets cached as HomePage:id as per the resolver, and the homepage is referencing the cache every time you go back to it. How is this happening?
Is there anything I'm doing wrong with this code?