使用 Apollo 和 GraphQL 缓存而不是 Vuex?
Using Apollo & GraphQL caching instead of Vuex?
我一直在尝试使用 Apollo 和 GraphQL。我读到过您可以使用缓存而不需要 Vuex - 但我不能全神贯注于如何做到这一点,除非创建某种将两者结合起来的反模式。
有没有人举例说明他们是如何处理这种情况的?
我在尝试什么:
使用 Vue Apollo 的 CLI 安装:
vue add apollo
在 ./vue-apollo.js 中设置配置后,我添加了一个导出到提供程序和默认选项:
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
}
在./router/index.js
导入 apollo 提供程序、选项和查询...
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
查询页面的函数
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('/')
})
}
查询首页内容的功能
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')
})
}
}
在每个之前:
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()
})
我的突变和解析器
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
}
}
}
问题
目前,我每次调用都有两个查询文件,一个用于远程,一个用于本地,其中包含针对查询的@client。是否可以有一个查询文件,但根据数据是否存在使其 @client
有条件?
我们是否必须 return 带有突变的 readQuery?或者我可以基本上只有 addHomePageMutation: (_, ctx, { cache }) => cache.writeQuery({ query: storeHomepage })
我们需要在变异之前阅读查询吗?我们是否需要将该数据传递给 writeQuery 方法?
最令人困惑的是,我对在不传递变量或改变查询的情况下存储主页数据感到困惑。最后,我只是将其恢复为仅使用“查询”,没有突变,但没有删除解析器。尽管如此,它仍然有效,数据根据解析器被缓存为 HomePage:id,并且每次返回时主页都会引用缓存。这是怎么回事?
这段代码有什么问题吗?
vue - 为什么不 useQuery
在组件中……就像通常 [在反应中] 一样?使用路由器看起来像个笑话......不可组合......一些子组件如何查询数据 - 道具钻取反模式?
- 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?
@client可以作为远程查询结果的一部分(字段)
- Do we have to return the readQuery with mutations? Or could I essentially just have addHomePageMutation: (_, ctx, { cache }) => cache.writeQuery({ query: storeHomepage })
突变必须 return 某些东西 - 突变结果的定义类型 - 它可以用简单的布尔 result
字段定义,突变可以 return true
值。
- 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?
- 加载代码应放在本地解析器中;
- 你应该在你的一个文件组件中使用
useQuery
我一直在尝试使用 Apollo 和 GraphQL。我读到过您可以使用缓存而不需要 Vuex - 但我不能全神贯注于如何做到这一点,除非创建某种将两者结合起来的反模式。
有没有人举例说明他们是如何处理这种情况的?
我在尝试什么:
使用 Vue Apollo 的 CLI 安装:
vue add apollo
在 ./vue-apollo.js 中设置配置后,我添加了一个导出到提供程序和默认选项:
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
}
在./router/index.js 导入 apollo 提供程序、选项和查询...
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
查询页面的函数
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('/')
})
}
查询首页内容的功能
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')
})
}
}
在每个之前:
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()
})
我的突变和解析器
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
}
}
}
问题
目前,我每次调用都有两个查询文件,一个用于远程,一个用于本地,其中包含针对查询的@client。是否可以有一个查询文件,但根据数据是否存在使其
@client
有条件?我们是否必须 return 带有突变的 readQuery?或者我可以基本上只有
addHomePageMutation: (_, ctx, { cache }) => cache.writeQuery({ query: storeHomepage })
我们需要在变异之前阅读查询吗?我们是否需要将该数据传递给 writeQuery 方法?
最令人困惑的是,我对在不传递变量或改变查询的情况下存储主页数据感到困惑。最后,我只是将其恢复为仅使用“查询”,没有突变,但没有删除解析器。尽管如此,它仍然有效,数据根据解析器被缓存为 HomePage:id,并且每次返回时主页都会引用缓存。这是怎么回事?
这段代码有什么问题吗?
vue - 为什么不 useQuery
在组件中……就像通常 [在反应中] 一样?使用路由器看起来像个笑话......不可组合......一些子组件如何查询数据 - 道具钻取反模式?
- 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?
@client可以作为远程查询结果的一部分(字段)
- Do we have to return the readQuery with mutations? Or could I essentially just have addHomePageMutation: (_, ctx, { cache }) => cache.writeQuery({ query: storeHomepage })
突变必须 return 某些东西 - 突变结果的定义类型 - 它可以用简单的布尔 result
字段定义,突变可以 return true
值。
- 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?
- 加载代码应放在本地解析器中;
- 你应该在你的一个文件组件中使用
useQuery