この記事の目次
Piniaの使い方とは
Pinia(ピーニャ)は、Vue の状態管理(いくつもの画面や部品で共有するデータの管理)のためのライブラリーです。Vue 公式ドキュメントは、以前の公式ライブラリーである Vuex はメンテナンスモード(新しい機能は追加されない状態)になっており、新しいアプリケーションには Pinia を使うよう勧めています。
部品どうしでデータを渡す基本は props と emit ですが、離れた画面どうしで同じデータを使いたいとき、何段もの親子を経由して渡すのは大変です。Pinia の「ストア」に置けば、どの部品からでも同じデータを読み書きできます。この記事では、2026年10月時点の Pinia 4.0.3 で動かした例で、ストアの作り方と使い方を説明します。
基本(ストアの3つの要素)
Pinia の公式ガイドでは、ストアは、部品の木構造に縛られない状態と処理を持つもので、state・getters・actions の3つの考え方があり、部品の data・computed・methods に当たると説明しています。
| ストアの要素 | 意味 | Composition API での書き方 |
|---|---|---|
| state | 共有するデータ | ref() |
| getters | state から計算した値 | computed() |
| actions | state を変える処理 | ふつうの関数 |
使う前に、アプリに Pinia を登録します(create-vue で Pinia を選ぶと、src/main.js に最初から書かれています)。
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
サンプルコード(実行結果つき)
src/stores/counter.js(create-vue が作る例そのもの)
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})
ストアを使う画面
<script setup>
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
const { count, doubleCount } = storeToRefs(counter)
</script>
<template>
<p>カウント {{ count }}/2倍 {{ doubleCount }}</p>
<button type="button" @click="counter.increment()">増やす</button>
</template>
storeToRefs は、ストアから state や getters を取り出しても、変更が画面に反映され続けるようにする関数です。ストアをそのまま分割代入(const { count } = counter)すると、つながりが切れてしまいます。actions(increment)は、counter.increment() のようにストアから直接呼びます。
動作確認(検証環境と結果)
- Vue 3.5.43、Pinia 4.0.3、Vue Router 5.3.1、Vite 8.3.3、Microsoft Edge、2026年10月。
- 最初は「カウント 0/2倍 0」、「増やす」を1回押すと「カウント 1/2倍 2」になりました。
- 別の画面(
/about)でも同じストアを読むようにし、ホームで2回増やしてからRouterLinkで移動すると、「2(2倍は 4)」と表示されました。 - ブラウザを再読み込みすると、値は 0 に戻りました。
Piniaの使い方の注意点
- ストアのデータは、再読み込みで消えます。 メモリの中に置かれているためです。残したいときは、localStorage などに保存する仕組みを別に作ります。
- 何でもストアに入れない: Pinia の公式ガイドは、ストアには、アプリのあちこちで使うデータ(ナビゲーションに出すユーザー情報や、何ページにもまたがる入力の途中経過など)を置き、1つの画面の中だけの状態(ある要素を見せるかどうか等)は部品の中に置くよう説明しています。
defineStoreの最初の引数('counter')は、ストアごとに違う名前にします。
Piniaの使い方でよくあるミス
app.use(createPinia())を忘れて、ストアを使うとエラーになる。- ストアを分割代入して、表示が変わらなくなる(
storeToRefsを使う)。 - 1つのストアに何でも入れて、どこで何が変わったか分からなくなる。
Piniaの使い方のチェックリスト
- [ ]
main.jsで Pinia を登録した - [ ]
defineStoreで、state・getters・actions を書いた - [ ] 取り出すときは
storeToRefsを使った - [ ] ストアに入れるのは、複数の画面で使うデータだけにした
Piniaの使い方のFAQ(よくある質問)
Q. Vuex と Pinia はどちらを学べばいいですか?
A. 新しく作るなら Pinia です。Vue 公式が新しいアプリには Pinia を勧めています。既存のプロジェクトが Vuex を使っているなら、その保守のために Vuex を読む必要があります。
Q. reactive() で作ったオブジェクトを export するのと何が違いますか?
A. 小さなアプリなら、それでも共有できます。Pinia の公式ガイドは、開発者ツールでの追跡や、ファイルを保存したときの再読み込みなしの反映(ホットモジュールリプレースメント)、サーバーサイドレンダリングへの対応などを、Pinia を使う理由として挙げています。
Q. Options API の形でストアを書けますか?
A. 書けます。defineStore に state・getters・actions を持つオブジェクトを渡す書き方もあります。
筆者の見解(Piniaの使い方)
Pinia は便利な分、何でもストアに入れたくなるのが落とし穴だと感じます。私は「2つ以上の画面で使うか」を入れる基準にすることを勧めます。1つの画面の中で完結するデータは、部品の ref で十分で、そのほうが流れを追いやすいからです。まずは create-vue が作る counter の例を読み、そこに自分のデータを1つ足すところから始めると理解が速いと考えます。
Piniaの使い方の関連項目
- Vue Routerの使い方|ルート定義・RouterLink・RouterView
- npm create vue@latestの使い方|Vueプロジェクト作成
- Vue 3 refとreactiveの違い|使い分けと落とし穴(近日公開)
- Vue 3 computedとwatchの違い|使い分けとwatchEffect(近日公開)
- localStorageの使い方|JSONの保存・容量・sessionStorageとの違い(近日公開)
