Piniaとは、Vue.jsの状態管理ライブラリです。
Vue2まではVuexがVue.jsの状態管理ツールとして利用されてきましたが、Vue3の公式ドキュメントではこのPiniaが状態管理ツールとして推奨されています。
今回はこのPiniaがVuexと比較してどこが違うのかについて、フロントエンド専門のプログラミング学習ツール『CodeDict(コードディクト)』を運営するコードディクト編集部が分かりやすく解説していきます。
目次
そもそも状態管理とは何なのか?
Piniaの解説をする前に状態管理とは何かをおさらいしておきましょう。
状態管理はアプリケーションのコンポーネント間で共有されるデータを管理するためのデザインパターンの実装です。
ユーザーに提示されるデータ全体の一貫性を確保するために利用されます。
SPAでは、ページという概念ではなく複数のコンポーネントでデータを操作し変更してからサーバーにAPIを通じてデータを送ります。これらの変更を管理する方法として『データの状態』が必要であり、VuexやPiniaなどの状態管理ライブラリを利用しています。
VuexやPiniaではデータはストアと呼ばれる場所で一元管理されるので、個々のコンポーネントでデータを持つ必要がなくなるというメリットがあります。
Piniaとは?
Vue.jsにおける状態管理ツールといえば、Vuexが有名であり公式からも推奨されていましたが、2020年9月にリリースされたVue3からはPiniaが状態管理ツールとして推奨されています。
以下は2021年にトロントで開催されたVue Conf 2021年のTweetですが、Vue.jsの開発者であるEvan You氏の講演時にVue3の推奨状態管理ツールがPiniaになったことを公言しています。
🔥 Beware!
The new @vuejs default recommendations!
Vue CLI ➡️ create-vue (npm init vue@next)
Vetur ➡️ Volar
Vuex ➡️ Pinia pic.twitter.com/dYcQpMvZ0R— VueDose (@VueDose) November 23, 2021
Piniaでは、
- State
- Getters
- Action
の3つの要素からストア(状態管理する場所)が出来ています。
それぞれの役割についてご紹介していきます。
State
Stateは管理するデータの入れ物の役割を持っています。
ここに定義したデータは Vueアプリケーション内の各コンポーネントから適宜取得・更新することが可能です。
import { defineStore } from 'pinia'
const useStore = defineStore('storeId', {
state: () => {
return {
counter: 0,
name: 'Eduardo',
isAdmin: true,
}
},
})
Getters
getters では state のデータに対する算出プロパティを定義します。
PiniaではStateから直接データを取得することも可能ですが、Stateにあるデータをソートして取得したいなどStateから取得するデータに一手間加えて取得したい場合にはGettersを利用します。
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
})
Action
Actionプロパティでは、stateの値を更新する際に利用します。
APIでデータを取得してstateに格納する、stateに入っているデータを更新するといったビジネスロジックを定義します。
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
actions: {
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
},
})
Piniaの導入方法
PiniaでState管理するまでの導入方法を見ていきます。
今回はVue3 + Vite + Pinia + TypeScript の環境を作成し、PiniaでState管理できるまでの導入方法を見ていきます。
基本的にはState管理までの導入方法はVuexとほとんど違いはなく、以下の4ステップState管理まで実装可能です。
- Piniaのインストール
- VueにPiniaをセットアップ
- storeファイルの作成
① Piniaのインストール
まずはPiniaをインストールします。
npm であれば、
npm install pinia
yarn を利用する場合は以下のでインストールできます。
yarn add pinia
② VueにPiniaをセットアップ
次にmain.tsにPiniaをセットアップします。
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
createApp(App).use(createPinia()).mount("#app");
上記のようにcreatePiniaをimportし、VueのcreateApp時にuseメソッドでcreatePiniaを実行してマウントするだけでPiniaのセットアップ完了です。
③ storeファイルの作成
次にstoreファイルを作成します。
import { defineStore } from "pinia";
export const useStore = defineStore({
id: 'store',
state: () => ({
person: {
name: '',
company: ''
}
})
});
ポイントとしてはidの値はユニークである必要があります。
idが重複していると、どちらかのstoreしか読み込まないようになっているのでエラーが起こります。
④ コンポーネントで表示
最後のstoreのstateで管理しているstateをコンポーネントで表示します。
表示方法も非常にシンプルでstoreファイルをインポートし、定義したstoreを呼ぶだけでstateを表示させることが可能です。
<script setup>
import { useStore } from "./store/index";
import { useCounterStore } from "./store/counter";
const store = useStore();
</script>
<template>
<div>会社名: {{ store.person.company }}</div>
<div>氏名: {{ store.person.name }}</div>
</template>
Vuexとの違い
同じVue.jsの状態管理ライブラリであるVuexとは明確に4つの違いがあります。
- TypeScript のフルサポート
- mutations の廃止
- ネストされたモジュールの廃止
それぞれ詳しく見ていきます。
TypeScript のフルサポート
Vue3にも対応しているVuex4.xではTypeScriptにTypeScriptに対応はしているものの完全にサポートされている訳ではありませんでした。
TypeScriptの型推論がサポートされておらず、対応させるためにはカスタムでラッパークラスを実装する必要がありました。
Piniaでは型推論までTypeScriptをフルサポートしているので、デフォルトでTypeScriptをを活かせる設計になっています。
mutations の廃止
Vuexでstateの値を更新する際にミューテーションで行っていましたが、Piniaではこのミューテーションは廃止されました。
VuexのStateの更新はミューテションでしか行えないという仕様でしたが、PiniaではどこからでもStateの更新を行うことが可能です。
このmutationを廃止すべきかはPinia のコミュニティでも議論されていました。
Add an option to disallow direct state modification from component
mutationがあることで、データの書き換えを限定し厳格に管理することを担保していました。
しかし、結局はactionメソッドを通してただstateの値を変更するという単一の操作しか行われていないためmutationは完全に不要だったとPiniaの開発者でありVue.jsのコアチームの一人でもある『Eduardo San Martin Morote』が言っています。
廃止によって可読性が高いコードに
VuexではState、Getters、Mutation、Actionとストアを扱う上では4つの構造を記述しなければならないためにコードが冗長していくの一つの問題でもありました。
Piniaではmutationの廃止され、全体的な記述の見直しが行われておりVuexと比較すれば可読性の高いコードになっています。
以下はVuexを使ったストアの記述です。
import { createStore } from "vuex";
const useCounterStore = createStore({
state() {
return {
count: 0,
};
},
mutations: {
setCount(state, count) {
state.count = count;
},
},
actions: {
increments({ commit }, currentNum) {
commit('setCount', currentNum++)
}
},
続いてこちらが、Piniaのストアです。
import { defineStore } from "pinia";
export const useCounterStore = defineStore("counter", {
state: () => ({
count: 0,
}),
actions: {
increments({ state }, currentNum) {
state.count = currentNum;
},
},
});
このようにmutationが廃止された分、スッキリし可読性が高いコードになっています。
ネストされたモジュールの廃止
Vuexでは複数のモジュールを1つのストアに持ち単一でストアを持つ概念でした。
1つのストアにまとめることで、名前空間を作成したり相互にネストしストアを構成していました。

しかし、ネストされたモジュールの構成はpiniaでは廃止され、以下のようにフラットにストアを持つ構成になっています。

Piniaでは一つ一つのstoreが分離されており、呼び出す際も該当のストアモジュールを直接呼び出しますが、Vuexでは単一のモジュールに集約したストアで管理する構造になっています。
ストアを格納するVuexでは『store』ディレクトリですが、Piniaでは『stores』と名付けられています。
これはPiniaがストアを単一のモジュールとしてではなく複数のモジュールとして扱っていることを強調するために命名しているそうです。
まとめ
Piniaは最新バージョンのVue3だけでなくVue2でも利用することが可能です。
Vuexと比較すると一番大きな違いは mutationが廃止されシンプルに書けるようになったという点でしょうか。
また、TypeScriptもフルサポートされており型推論が使えるというのも個人的には嬉しい点です。
Vue3を利用する際は状態管理ライブラリとしてぜひPiniaをお試しください。
Piniaについてご紹介しました。
コードディクトではフロントエンド専門の実践特化型のプログラミング学習サービスです。
コーディングからフロントエンジニアまでの学習をカバーしており、コーディングしながら実践的に学習することで知識ではなく『スキル』が身につけられるサービスとなっております。
現在無料体験キャンペーンを行っていますので、気になる方はぜひ無料体験を利用してみてください。
最近のコメント