【问题标题】:Using Apollo & GraphQL caching instead of Vuex?使用 Apollo 和 GraphQL 缓存而不是 Vuex?
【发布时间】:2020-11-17 08:39:06
【问题描述】:

我一直在试验 Apollo 和 GraphQL。我已经读到您可以利用缓存而不是需要 Vuex - 但我无法解决如何做到这一点,而不创建某种将两者结合起来的反模式。

有没有人举例说明他们是如何处理这种情况的?

我正在尝试什么:

使用 Vue Apollo 的 CLI 安装:

vue add apollo

在./vue-apollo.js中设置好配置后,我添加了一个导出到provider和默认选项:

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. 我们必须返回带有突变的 readQuery 吗?或者我可以基本上只有addHomePageMutation: (_, ctx, { cache }) => cache.writeQuery({ query: storeHomepage })

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

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

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

【问题讨论】:

  • 是的,谢谢。我对文档感到困惑,所以发布了这个期待更多帮助。我们不能只使用 writeData 而不是创建突变和解析器吗?我们每次都需要传递变异变量吗?一切都需要异步吗?人们是否对数据和本地使用重复查询?我希望看到一些处于类似情况的人发布他们的解决方案示例。抱歉,我可能对我的帖子的意图不太清楚。从那以后我已经找到了解决方法,但不确定它是否是最好的解决方案。不过,感谢您的反对票。
  • useQuery/useMutation 是高级 API,writeQuery/writeData 是在特殊情况下使用的低级 API ...查询和突变并不总是需要 vars(查询可以改变数据,但按照惯例应该是一个突变)...... [真的人们在什么时候可以使用反应? ;)] ...此代码/解决方法是恕我直言,滥用 apollo ...编写解析器而不是减速器,它统一了本地/远程数据访问
  • 谢谢,这很有帮助。我已经更新了我的解决方案并有一些相关的问题。我仍然对突变感到有些困惑。你介意回答这些吗?哈哈,关于 Vue - 我喜欢它。两者我都用过,但个人一直喜欢 Vue,它是 jsx 上的单文件组件。

标签: vue.js caching graphql vuex apollo


【解决方案1】:

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

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

@client 可以作为远程查询结果的一部分(字段)

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

突变必须返回一些东西——突变结果的定义类型——它可以用简单的布尔result字段来定义,突变可以返回true值。

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

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

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

没有显示代码,不知道

  1. 这段代码有什么问题吗?
  • 加载代码应该放在本地解析器中;
  • 你应该在你的一个文件组件中使用useQuery

【讨论】:

  • 谢谢,这很有帮助!我最初只在组件中使用查询。我在路由器中执行此操作的原因允许我在页面导航之前加载页面,并在页面不存在时控制条件,因为它们都是动态的。它具有更流畅的用户体验,而不是加载页面,然后检查页面是否存在,如果不存在则重定向到其他地方;在路线之前加载它也感觉更快。
猜你喜欢
  • 2021-05-09
  • 2020-09-04
  • 2021-08-08
  • 2020-07-07
  • 2020-11-17
  • 2021-07-05
  • 2018-05-26
  • 2018-10-16
  • 2019-01-09
相关资源
最近更新 更多