I can't get multiple components accessing the same store respond to updates, until I mess with a dom element to trigger new render.
In my Pinia store, I have an array, and an update method:
let MyArray: IMyItem[] = [
{ id: 1,
name: "First Item",
}, ....
let SelectedItem = MyArray[0]
const AddItem = ( n: string, ) => {
MyArray.push({ id: createId(), name: n, });
};
return { MyArray, SelectedItem, AddItem }
In one Vue component, I have text inputs and a button to call the store's method:
function handle() {store.AddItem(name.value));
In another Vue component, on the same parent, I use a for loop to display allow for selecting an item:
<div v-for="item in store.MyArray">
<input type="radio"...
No changes with these efforts:
const { MyArray } = storeToRefs(store);
const myArray = reactive(store.MyArray);
// also watching from both components...
watch(store.MyArray, (n, o) => console.dir(n));
// also... lots of other stuff.
const myArray = reactive(store.MyArray);
watch(myArray, (n, o) => console.dir(n));
I also experimented with <form @submit.prevent="handle">
triggering nextTick
by adding a string return to the store's method.
I assume the reason clicking around makes it work is because I'm changing the the store's SelectedItem
, and its reactivity calls for re-rendering, as it is v-model
for a label.
The docs say Array.push should be doing it's job... it just isn't bound the same way when used in v-for
.
What's needed to trigger the dom update? Thanks! 💩
As comments pointed out, the main issue is your store state is not declared with the Reactivity API, so state changes would not trigger watchers and would not cause a re-render.
The solution is to declare MyArray
as a reactive
and SelectedItem
as a ref
:
// store.js
import { defineStore } from 'pinia'
import type { IMyItem } from './types'
import { createId } from './utils'
👇 👇
import { ref, reactive } from 'vue'
export const useItemStore = defineStore('item', () => {
👇
let MyArray = reactive([{ id: createId(), name: 'First Item' }] as IMyItem[])
👇
let SelectedItem = ref(MyArray[0])
const AddItem = (n: string) => {
MyArray.push({ id: createId(), name: n })
}
return { MyArray, SelectedItem, AddItem }
})
If using storeToRefs()
, make sure to set the ref
's .value
property when updating the SelectedItem
:
// MyComponent.vue
const store = useItemStore()
const { SelectedItem, MyArray } = storeToRefs(store)
const selectItem = (id) => {
👇
SelectedItem.value = MyArray.value.find((item) => item.id === id)
}
But in this case, it's simpler to use the props off the store
directly:
// MyComponent.vue
const store = useItemStore()
const selectItem = (id) => {
store.SelectedItem = store.MyArray.find((item) => item.id === id)
}