Home > Back-end >  Component won't update in Vue
Component won't update in Vue

Time:10-14

I'm using pinia to store data in my Vue app. There is a component called ListTag:

<template>
  <div
    v-for="(tag, index) in visibleTagItems"
    :key="index"
    
  >
    <q-chip
      :removable="tagsWantToggle"
      size="8px"
      outline
      :color="tag.color"
      :
      
      @remove="removeTag(index)"
    >
      {{ wantCircle(index, tag.label) }}
      <q-tooltip : :delay="1000" :offset="[0, 10]"
        >{{ tag.label }}
      </q-tooltip>
    </q-chip>

    <q-btn-dropdown
      v-if="tagsWantToggle && index == tagItems.length - 1 && wantDropdown"
      flat
      color="grey"
      
      label=""
      dropdown-icon="expand_more"
      size="8px"
    >
      <q-list
        v-for="(tagDefault, index) in dropdownTagItems"
        :key="index"
        :
      >
        <q-item clickable v-close-popup @click="addTag(tagDefault)">
          <q-item-section>
            <q-item-label>{{ tagDefault.label }} </q-item-label>
          </q-item-section>
        </q-item>
      </q-list>
    </q-btn-dropdown>
  </div>
</template>

<script>
import { defineComponent, ref, onMounted } from "vue";
import { useCounterStore } from "../../stores/database";

export default defineComponent({
  name: "list-tags",
  props: {
    tagsWantToggle: {
      type: Boolean,
      default: false,
    },
    tagItems: {},
  },
  setup(props) {
    const store = useCounterStore();

    var wantDropdown = ref(props.tagsWantToggle);

    const visibleTagItems = ref(props.tagItems);

    const storeTagItems = store.tags;

    var dropdownTagItems = null;
    if (store.selectedEmail.tagItems) {
      dropdownTagItems = storeTagItems.filter(
        ({ label: id1 }) =>
          !store.selectedEmail.tagItems.some(({ label: id2 }) => id2 === id1)
      );
    }
    return {
      dropdownTagItems,
      storeTagItems,
      wantDropdown,
      visibleTagItems,
    };
  },
  methods: {
   ...
  },
});
</script>

<style></style>

The parent component called Content contains this code:

<ListTags  :tagsWantToggle="true" :tagItems="store.selectedEmail.tagItems" />

When the page is loaded, the selectedEmail is just an empty object. Later, as I open one email the selected email will be filled with some data, but the ListTags will not be visible. It is strange, because in the Content file I'm using this code: <div >{{ store.selectedEmail.message }}</div> and it works perfectly. It updates if another email is selected.

How could I update the tags inside ListTag?

CodePudding user response:

These are notes from Pinia team:

  • Store is an object wrapped with reactive, meaning there is no need to write .value after getters but, like props in setup, we cannot destructure it
  • In order to extract properties from the store while keeping its reactivity, you need to use storeToRefs()
.

So, in your case, components are not updated because storeTagItems is not reactive. To make it reactive, simply destructure store with storeToRefs().

const {tags: storeTagItems} = storeToRefs(store))

CodePudding user response:

This code inside setup function:

  const storeTagItems = store.tags;
  var dropdownTagItems = null;
  if (store.selectedEmail.tagItems) {
    dropdownTagItems = storeTagItems.filter(
      ({ label: id1 }) =>
        !store.selectedEmail.tagItems.some(({ label: id2 }) => id2 === id1)
    );
  }

... only runs once: when the setup() function is run. It doesn't run every time store.selectedEmail.tagItems or store.tags change. In other words, it's not "reactive".

To make it reactive, write a computed:

const dropdownTagItems = computed(() =>
  store.tags.filter(
    ({ label }) =>
      !store.selectedEmail.tagItems.some(({ label: l }) => label === l)
  )
);
  • if store.tags is nullable, replace store.tags.filter with (store.tags || []).filter.
  • if store.selectedEmail or its tagItems are nullable, replace store.selectedEmail.tagItems.some with
    (store.selectedEmail?.tagItems || []).some

dropdownTagItems will now react to any change in store.tags or store.selectedEmail.tagItems. It's reactive.

Notes:

  • if you use dropdownTagItems in more than one place, consider writing a store getter and move the above computed in that getter, so you don't need to repeat yourself in multiple components.
  • if you use storeTagItems anywhere else in the component, you should make it reactive with any of these methods:
    a) use store.tags directly;
    b) make it a computed: const storeTagItems = computed(() => store.tags)
    c) use the storeToRefs helper importable from pinia:
    const { tags: storeTagItems } = storeToRefs(store)
  • Related