首页 > 解决方案 > 为什么用 vue-apollo 在两个独立组件之间共享组件数据?

问题描述

我正在使用 vue 和 vue-apollo 开展一个新项目。

我有一个显示用户名的组件(UserShow.vue):

<template>
    <div v-if="!this.$apollo.queries.user.loading">
        Your name is: {{user.firstname}}
    </div>
</template>
<script>
    import gql from "graphql-tag";
    export default {
        apollo: {
            user: {
                query: gql`{
                   user (id: 1) {
                     id
                     firstname
                   }
                }`
            }
        }
    }
</script>

和一个用于编辑的组件(UserEdit.vue):

<template>
    <div v-if="!this.$apollo.queries.user.loading">
        Edit your name: <input v-model="user.firstname" />
    </div>
</template>

<script>
    import gql from "graphql-tag";
    export default {
        apollo: {
            user: {
                query: gql`{
                   user (id: 1) {
                     id
                     firstname
                   }
                }`
            }
        }
    }
</script>

两个组件都显示在同一页面上,绝对不涉及突变。只是这两个简单的组件。就是这样

只要我在输入字段中更改名称,用户名就会在视图中更新。

这对我来说很奇怪,我不喜欢它。

Apollo 正在执行查询并填充data()每个组件的 vue 属性。但是为什么数据会以某种方式共享呢?data只要我不将它传递给子组件(就像输入字段中的 v-model 一样),vue 组件中的组件应该是该组件私有的。

如果我查看我的 Apollo Dev Console 到缓存中,我看不到名字的变化。那么它是怎样工作的?

如果我不想要这种行为,我只有一个奇怪的选择:

我可以像这样向查询添加另一个属性:

<template>
    <div v-if="!this.$apollo.queries.user.loading">
        Edit your name:
        <input v-model="user.firstname" />
    </div>
</template>

<script>
    import userQuery from "./user";
    import gql from "graphql-tag";
    export default {
        apollo: {
            user: {
                query: gql`{
                   user (id: 1) {
                     id
                     firstname
                     age         // added to create a different query
                   }
                }`
            }
        }
    }
</script>

在查询中添加“年龄”会改变行为。那更奇怪了!如何编写具有这种行为的可靠组件?还是我错过了一些重要的概念?

源代码可以在这里找到: https ://github.com/kicktipp/hello-apollo

错误或功能?

标签: vue.jsvuejs2graphqlapollo-clientvue-apollo

解决方案


我看了你的代码,我很确定我知道发生了什么。

如果你通读这个线程,你会发现查询返回的数据最初是由 Apollo 设计的,是不可变的(你不应该将它用作v-model)。事实上,它曾经被冻结,因此尝试将其用作数据源导致反应性中断。

然后这发生了。现在查询结果是可变的,你正在改变 Apollo 的内部数据。

这就解释了为什么一个更新会立即修改具有相同查询的另一个组件的显示输出。

尝试这样的事情:

import userQuery from './user';

export default {
  data() {
    return { user: {} };
  },
  apollo: {
    user: {
      query: userQuery,
      manual: true,
      result({ data }) {
        this.user = { ...data.user };
      },
    },
  },
};

请注意以下事项:

  • user被初始化在data
  • manual: true已设置,因此userVue Apollo 不会自动设置
  • result我们设置this.user使用扩展(或 Object.assign)来避免复制引用。如果对象有多个级别,请考虑使用cloneDeep 之类的东西。

您需要在您打算改变查询结果的所有地方进行类似的修改。


推荐阅读