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, replacestore.tags.filter
with(store.tags || []).filter
. - if
store.selectedEmail
or itstagItems
are nullable, replacestore.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) usestore.tags
directly;
b) make it acomputed
:const storeTagItems = computed(() => store.tags)
c) use thestoreToRefs
helper importable frompinia
:
const { tags: storeTagItems } = storeToRefs(store)