👏

【祝公式化!🌸】PiniaがVue.js公式のレポジトリとなり、公式の推奨ライブラリとなりました!&早速試してみる

2021/12/18に公開

Piniaが公式の仲間入りへ!

Vuejsの推奨状態管理ライブラリがPiniaに!

早速Piniaを試してみる

npm init vue@nextで作成されるフォイルを覗いてみましょう
image.png
Piniaを使用するか聞かれるのでYesにします。
フォルダ構成(一部抜粋)
image.png

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を使用する必要があります。詳しくは公式ドキュメントをどうぞ。

https://v3.vuejs.org/api/sfc-script-setup.html

本題

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.gif

まとめ

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