What is the reason for the sharing of component data between two separate components using vue-apollo?

Currently, I am engaged in a fresh project utilizing vue along with vue-apollo.

There is one component dedicated to displaying the user's name (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>

Additionally, there exists another component specifically for editing purposes (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>

Both of these components are displayed on the same page without any involvement of mutations. These simple components encapsulate the functionality.

Upon modifying the name within the input field, the username gets automatically updated in the View.

This behavior seems peculiar and not something that aligns with my preferences.

Apollo conducts the query and populates the vue data() property for each component. However, I find it odd how the data appears to be shared to some extent. The data in a vue component ought to remain private unless explicitly passed to a subcomponent (as done with v-model in the input field).

Upon inspecting the Apollo Dev Console and delving into the Cache, the change in firstname does not seem to reflect there. So, how exactly is this functioning?

If this behavior is not desired, there seems to be only one unusual solution:

An extra attribute can be included in the query as shown below:

<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>

Incorporating "age" into the query brings about a change in behavior. This alteration appears even more puzzling! How can reliable components be constructed given such a behavior? Have I overlooked a crucial concept?

The source code can be accessed here: https://github.com/kicktipp/hello-apollo

Bug or feature?

Answer №1

After reviewing your code, it seems clear to me what the issue is.

Upon reading through this discussion, it's evident that Apollo initially designed query results to be immutable (not suitable for use as a v-model). Initially, these results were frozen, causing reactivity issues when used as data sources.

However, there was a change detailed in this update. Now, query results are mutable, allowing for direct manipulation of Apollo's internal data.

This change explains why updating one component with an identical query would instantly affect another component's display output.

To address this issue, consider implementing the following:

import userQuery from './user';

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

Take note of the following:

  • user being initialized in data
  • manual: true set to prevent automatic setting of user by Vue Apollo
  • In the result section, we utilize spread syntax (or Object.assign) to assign this.user without referencing the original object. For multi-level objects, consider using something like cloneDeep.

Similar adjustments will need to be made throughout your codebase where mutation of query results is intended.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Why is the [Vue alert]: Prop error caused by custom validator not passing for prop "value"?

I am working on a nuxt.js app that utilizes the vuejs-datepicker library: <template> <!-- ... --> <DatePicker :value="datePicker.value" /> <!-- ... --> </template> As part of my project, I have several date variables: ...

utilize computed properties to automatically update components when Vuex state changes

Currently, I'm in the process of developing a basic movie application using Vue and Vuex. My goal is to allow users to add movies to a favorites list by clicking a button. The movies are stored in the Vuex state; however, I'd like the text on the ...

Exploring Vue: Utilizing Custom Components for Array Input Bindings

Vue's v-bind syntax allows for binding multiple checkboxes with different value attributes to the same array, which stores the values of all checked checkboxes. Check out this example: https://vuejs.org/guide/essentials/forms.html#checkbox But can we ...

The attribute 'positive_rule' is not found within the structure '{ addMore(): void; remove(index: any): void;'

data() { return { positive_rule: [ { positive_rule: "", }, ], }; }, methods: { addMore() { this.positive_rule.push({ positive_rule: "", }); }, ...

Ways to implement Toasted within an export default {} block

Recently, I've been experimenting with the implementation of the Toasted package in my project. However, I've run into some challenges trying to grasp its functionalities. In my project, I utilize a utility called TreatErrors.js designed to mana ...

Using dynamic mdi svg icons with Vuetify

I'm struggling to display a dynamic v-icon within a v-select component. I want to replace the icon name with its imported value <v-select v-model="data.type" dense :items="typeItems" :label="$tc('Type')"> & ...

It appears that Next.js caches files in a route ending with _next/data/[path].json, which can prevent getStaticProps from executing during server-side rendering

When sharing a link on platforms like Discord and Slack, an issue arises where a URL preview is generated by sending a request to the link. The link structure in question is as follows: www.domain.com/ctg/[...ids]. https://i.stack.imgur.com/Nl8MR.png Wit ...

Top tips for utilizing CSS in a web component library to support various themes

Our team is currently in the process of developing a comprehensive design system that will be utilized across multiple projects for two distinct products. Each product operates with its own unique brand styleguide which utilizes design tokens, such as: Th ...

Tips on storing information within a Vue instance

Seeking a simple solution, all I need is to save data retrieved after an AJAX post in the Vue instance's data. See below for my code: const VMList = new Vue({ el: '#MODAL_USER_DATA', data: { user: []//, //userAcc: [] }, met ...

Building a custom Vuetify extension to enhance core features

I am currently working on developing a plugin-based component library to ensure consistency across various product lines using vuetify. However, when I try to install the library and add the components, I encounter multiple errors related to the dark theme ...

Ways to implement a package designed for non-framework usage in Vue

Alert This may not be the appropriate place to pose such inquiries, but I am in need of some guidance. It's more about seeking direction rather than a definitive answer as this question seems quite open-ended. Overview I've created a package th ...

Guide to implementing vue i18n $t method in vuex getters for vue 3

How do I incorporate i18n $t into my getters to retrieve a static label? I attempted importing it in the following way: import { i18n } from '../../locales/i18n.js'; const getters = { guaranteePolicies: state => { let guaranteesS ...

Version 13.5 of NextJS is triggering errors in the GraphQL schema

Ever since I updated to NextJS 13.5, I've been encountering these errors specifically when deploying on Vercel (although everything works fine locally): Error: Schema must contain uniquely named types but contains multiple types named "h". at new Gr ...

Clicking on multiple instances of the same Vue.js component (popover) results in displaying identical data

Attempting to display an AJAX response in a popover shown by clicking an icon (a custom Vue component) brings about a challenge. The issue arises when there are multiple instances of this component, dynamically rendered through the v-for directive within a ...

Encountered an error: Vue is not recognized within Laravel environment

While working on a Laravel application with Vue 3, I encountered an issue. When trying to load the welcome.blade.php file, I couldn't see the Vue file content and received the following error in the console: Uncaught ReferenceError: Vue is not defined ...

Webpack is stuck during the building process for the vue.common.js file

I recently set up a new Laravel application on my VPS and encountered an issue while trying to build it. The problem occurs when webpack attempts to build node_modules/vue/dist/vue.common.js as the process hangs. Here is the terminal output (project name ...

Understanding Vue.js props parameters

Can VueJs pass props as functions? <template> <line-chart class="card-content" :chartData="lineData2('Temp')" :options="options" :width="800"> </line-chart> </template> Is it possible to use t ...

Using Vue components in NativeScript-Vue popups: A comprehensive guide

To initiate the popup, I include the following code in a root component: import parentt from "./parentt.vue"; . . . this.$showModal(parentt, { fullscreen: true, }); The contents of parentt.vue are as follows: <template> <StackLayout> ...

Updating the color of a v-chip in vuetify dynamically

Just starting out with vuejs and vuetify. I recently watched a tutorial on vuetify on YouTube, where the instructor set the color of v-chip in this way. <v-flex xs2 sm4 md2> <div class="right"> <v-chip ...

Using the dot operator to load an image

Is it possible to using the dot operator to load an image? Let's talk about this as a sample image URL <img src={{GET_PROFILE_DATA.googleProfileData.fullName}} alt="profile" class="home-screen-profile-image"> Take note of the unusual looking ...