## 事象 以下のように[[Pinia]]で生成したStoreを[[分割代入 (JavaScript)|分割代入]]すると、データが[[リアクティブ]]ではなくなってしまう。`+`ボタンをクリックしてもカウントが増えない。 `stores/counter.ts` ```ts import { defineStore } from "pinia"; import { ref } from "vue"; export const useCounterStore = defineStore("counter", () => { const count = ref(0); function increment() { count.value++; } return { count, increment }; }); ``` ```html <script setup lang="ts"> import { useCounterStore } from "./stores/counter"; const { count, increment } = useCounterStore(); </script> <template> <h1>Hello</h1> <div>{{ count }}</div> <button @click="increment">+</button> </template> ``` なお、[[Composable]]を使った場合は[[リアクティブ]]である。 `composables/useCounter.ts` ```ts import { ref } from "vue"; export function useCounter() { const count = ref(0); const increment = () => { count.value++; }; return { count, increment }; } ``` `App.vue` ```html <script setup lang="ts"> import { useCounter } from "./composables/useCounter"; const { count, increment } = useCounter(); </script> <template> <h1>Hello</h1> <div>{{ count }}</div> <button @click="increment">+</button> </template> ``` ## 原因 直接[[リアクティブ]]な値 (`ref(...)`) を返却する[[Composable]]とは異なり、[[Pinia]]では`defineStore`を通じた返却を行うため。 ## 解決方法 方法は2通りある。個人的には1つ目の方法が好き。『storeは分割代入しない』というルールさえ守っておけば、予期せぬ実行時不具合を回避できるため。 ### 分割代入を使用しない [[分割代入 (JavaScript)|分割代入]]を使わなければ当然問題は解決する。こだわりがない場合は一番確実。 ```html <script setup lang="ts"> import { useCounterStore } from "./stores/counter"; const counterStore = useCounterStore(); </script> <template> <h1>Hello</h1> <div>{{ counterStore.count }}</div> <button @click="counterStore.increment">+</button> </template> ``` ### storeToRefsを使う 公式ドキュメントに案内されている`storeToRefs`でstoreを包んであげる。 <div class="link-card"> <div class="link-card-header"> <img src="https://pinia.vuejs.org/logo.svg" class="link-card-site-icon"/> <span class="link-card-site-name">pinia.vuejs.org</span> </div> <div class="link-card-body"> <div class="link-card-content"> <p class="link-card-title">Defining a Store | Pinia</p> <p class="link-card-description">Intuitive, type safe, light and flexible Store for Vue</p> </div> </div> <a href="https://pinia.vuejs.org/core-concepts/#Destructuring-from-a-Store"></a> </div> ```html <script setup lang="ts"> import { storeToRefs } from "pinia"; import { useCounterStore } from "./stores/counter"; const s = useCounterStore(); const { count } = storeToRefs(s); const { increment } = s; </script> <template> <h1>Hello</h1> <div>{{ count }}</div> <button @click="increment">+</button> </template> ```