使用 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
    }
  }
}

问题

  1. 目前,我每次调用都有两个查询文件,一个用于远程,一个用于本地,其中包含针对查询的@client。是否可以有一个查询文件,但根据数据是否存在使其 @client 有条件?

  2. 我们是否必须 return 带有突变的 readQuery?或者我可以基本上只有 addHomePageMutation: (_, ctx, { cache }) => cache.writeQuery({ query: storeHomepage })

  3. 我们需要在变异之前阅读查询吗?我们是否需要将该数据传递给 writeQuery 方法?

  4. 最令人困惑的是,我对在不传递变量或改变查询的情况下存储主页数据感到困惑。最后,我只是将其恢复为仅使用“查询”,没有突变,但没有删除解析器。尽管如此,它仍然有效,数据根据解析器被缓存为 HomePage:id,并且每次返回时主页都会引用缓存。这是怎么回事?

  5. 这段代码有什么问题吗?

vue - 为什么不 useQuery 在组件中……就像通常 [在反应中] 一样?使用路由器看起来像个笑话......不可组合......一些子组件如何查询数据 - 道具钻取反模式?

  1. 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可以作为远程查询结果的一部分(字段)

  1. 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 值。

  1. Do we need to read the queries before mutating? And do we need to pass that data through to the writeQuery method?

不,这不是必需的,只需传递匹配的结构数据。

  1. 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?

没有显示代码,不知道

  1. Is there anything I'm doing wrong with this code?
  • 加载代码应放在本地解析器中;
  • 你应该在你的一个文件组件中使用 useQuery