👏
【祝公式化!🌸】PiniaがVue.js公式のレポジトリとなり、公式の推奨ライブラリとなりました!&早速試してみる
Piniaが公式の仲間入りへ!
Vuejsの推奨状態管理ライブラリがPiniaに!
早速Piniaを試してみる
npm init vue@nextで作成されるフォイルを覗いてみましょう
Piniaを使用するか聞かれるのでYesにします。
フォルダ構成(一部抜粋)
main.ts
main.ts
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
既にPiniaを使用する為のセットアップが完了しています。
counter.ts
counter.ts
import { defineStore } from 'pinia'
export const useCounterStore = defineStore({
id: 'counter',
state: () => ({
counter: 0
}),
getters: {
doubleCount: (state) => state.counter * 2
},
actions: {
increment() {
this.counter++
}
}
})
ここでStoreの定義、状態を取得する為のgettersと状態を操作する為のactionsが定義がされています。Storeはいくつでも作成できますが、idは一意である必要があります。
App.vue(一部抜粋)
App.vue
<script setup lang="ts">
import HelloWorld from '@/components/HelloWorld.vue'
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<HelloWorld msg="You did it!" />
<nav>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
</nav>
</div>
</header>
<router-view />
</template>
<script>タグのデフォルトが<script setup>となっています。
基本的にはCompositionAPIと変わらないのですが、<script setup>を使うと、コンポーネントをimportするだけで使用できるようになるのと、refやreactiveで宣言したリアクティブな値をreturnせずにテンプレート内で使用することができ、コードの見通しが良くなります。只、親コンポーネントから子コンポーネントのインスタンスを参照する時に、子コンポーネント側でdefineExposeをする必要があったり、propsやemitの定義にはdefinePropsやdefineEmitsを使用する必要があります。詳しくは公式ドキュメントをどうぞ。
本題
HelloWorld.vue を書き換えます。
HelloWorld.vue
<script setup lang="ts">
import { useCounterStore } from "@/stores/counter";
const {counter,doubleCount,increment}=useCounterStore()
</script>
<template>
<h1 class="green">-doubleCount-{{counterStore.doubleCount}}</h1>
<button @click="counterStore.increment">カウント増加</button>
</template>
結果
期待通り動いています!
まとめ
Piniaでの状態管理はとても簡単です。只、デフォルトのstoreの定義の仕方だと、TypeScriptの恩恵を受けるためにasを使って型アサーションしなければならなかったりするのですが、CompositiionAPIを使うことで、よりシンプルにstoreを定義でき、TypeScriptの恩恵も受けやすくなります。
store.ts
export const useCartStore = defineStore('cart', () => {
const cart = ref<Item[]>([])
//getters
const getCartItems = () => cart.value
const getTotalFee = () => cart.value.reduce((sum, item) => sum + item.price, 0)
//setters
const addItemToCart = (item: Item) => cart.value.push(item)
return {
getCartItems,
getTotalFee,
addItemToCart
}
})
Discussion