はじめに
煽り気味のタイトルですみません。Vuexは使わない方がいいという話ではなく、別の有力な選択肢が出てきたというレベルの話であると最初に断っておきます。
みなさん、Piniaという状態管理ライブラリをご存知ですか?僕は昨日知りました。
調べてみるとどうやら先月Vueの公式リポジトリ入りをしており、今後さらに注目が集まるライブラリになりそうです。
* ちなみにPiniaはVuexを置き換えるものではなく、Vuexは今後も開発を継続していくようです(現在はVuex5を開発中)。
Vueの状態管理といえばVuexというイメージがありますが、TypeScriptとの相性が良くないだとか、そもそも冗長だとかで長らくVue3時代の状態管理のベストプラクティスがよくわからない状況が続いていました(?)
僕の知っている限りではVue状態管理の方法は
1. Vuex
2. provide/inject
3. 単にグローバルでリアクティブ変数を宣言する
4. Pinia
の4つですが、1の問題は前述した通りで、2、3はシンプルですがプロダクトやチームの規模によっては無秩序になりやすいという問題があります。
その点Piniaはシンプルで型安全かつパフォーマンスも良いというので、かなり有力な候補になり得るのではないでしょうか。
目次
基本的な使い方
導入は簡単
公式より
yarn add pinia
import { createPinia } from 'pinia'
// ...
app.use(createPinia())
これだけ
ストアはdefineStoreで定義
ぱっと見そんなにVuexと変わらないので、Vuex利用者は特に説明がなくても理解できると思います。
第一引数はアプリケーション内でユニークなキー
第二引数はストアの定義となるオブジェクトで、基本はstate,getters,actionsの3つのプロパティを指定
vuexと違いmutationsが存在しないのでよりシンプルですね
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return {
count: 0,
}
},
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
}
})
使用する際は
<script lang="ts">
import { defineComponent } from 'vue'
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
export default defineComponent({
setup() {
const counterStore = useCounterStore()
// toRefsだとreactivityが壊れるので注意
const { count } = storeToRefs(counterStore)
return {
counterStore,
count
}
},
})
</script>
<template>
<div>{{ count }}</div>
<div>{{ counterStore.double }}</div>
<button @click="counterStore.increment()" > increment! </button>
</template>
<script setup>記法で書くと ※ この記法を知らない方はここを参照
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const counterStore = useCounterStore()
const { count } = storeToRefs(counterStore)
</script>
<template>
<div>{{ count }}</div>
<div>{{ counterStore.double }}</div>
<button @click="counterStore.increment()" > increment! </button>
</template>
基本的な使用方法は以上です。
storeToRefsでリアクティブを維持したまま分割代入可能です。
gettersプロパティはcomputedと同様にリアクティブです。
おまじないが少なくて作業中に頭が混乱するのを防げそうですね。
補完もバッチリ効きます。
ちなみに、store.count++ とかstore.count = 10とかも可能です
実態はreactive()で作成したリアクティブオブジェクトのラッパーにすぎないのでこういうこともできちゃいます。
実際の運用ではstateを直接変更するのは禁止すべきかもしれませんね。
僕の場合、個人開発ではpiniaっぽいことをわざわざライブラリ無しでやっていたので、まさに自分が求めていたものが既に存在していたと知り感動しました。
補足
- 他のstoreにアクセスしたい場合
この場合もシンプルで、単に使用箇所でストアを取得しプロパティにアクセスするだけです。
import { useOtherStore } from './otherStore'
export const useCounterStore = defineStore('counter', {
state: () => {
return {
count: 0,
}
},
getters: {
other: (state) => {
const other = useOtherStore()
return other.num * state.count
}
},
})
コメント