Search code examples
vue.jsvue-componentvue-apollo

Apollo query from one component updates all the siblings in Vue


I have a Vue component with a list of items populated from a DB via Apollo:

<DeviceInfo camId="abcd"/>
<DeviceInfo camId="efgh"/>
<DeviceInfo camId="qwer"/>

When a response arrives via Apollo all three DeviceInfo components get updated with the same data at the same time. In the end they all have the very last response from the DB. I would expect the query to update its own component only.

Any suggestions why the data is shared?

What I know:

  1. the DB responses are correct and contain data for the right camId as far as apollo/data/updated function.
  2. Vue browser dev-tools show identical data objects for all DeviceInfo siblings.
  3. I get the same behavior with v-for
<v-flex v-for="item in data.listUserDevices.items" :key="item.device">
   <DeviceInfo :camId="item.device"/>
</v-flex>

Here is the full code of DeviceInfo component:

<template v-if="hydrated">
      <h2>camId: {{camId}} / {{ data.getLatestDeviceState.items[0].device }}</h2>
</template>


<script>
import gql from "graphql-tag";

const DEV_INFO_QUERY = gql`query getLatestDeviceState($device: String)
  {
    getLatestDeviceState(device: $device) {
      items {
        device
        timestamp
        version
      }
    }
  }
`;

export default {
  name: "DeviceInfo",
  props: {camId: String},
  data() {
      return dt;
    },
  async mounted() {
    await this.$apollo.provider.defaultClient.hydrated();
    this.hydrated = true;
  },
  apollo: {
    data: {
      query:  () => DEV_INFO_QUERY,
      variables: function() { 
        return {device: this.camId}
      },
      update: data => {
                return data;
      }
    }
  }
};

  let dt = {
    data: {
      hydrated: false,
      getLatestDeviceState: {
        items: [{device:"Loading ..."}]
      }
    }
  };

</script>

Solution

  • dt (short for "data template" I assume) is defined in your component definition so all instances would share the same object.

    An easy solution is to use it as a template but break the object reference in your data function, ie

    data() {
      return {...dt}
    }