※ 当ブログ「日々是事始め(コレコト)」はプロモーションを含みます。
ログイン中のユーザー名を、ヘッダーにもマイページにも表示したい。props で親から子へ、さらにその子へ…とデータを延々と手渡ししていく「バケツリレー」に、私はすぐ音を上げました。この「画面をまたいで同じデータを共有したい」場面で登場するのが Pinia(ピニア)という状態管理ライブラリです。ただし、何でも Pinia に入れればいいわけではありません。この記事では「いつ使うか」の線引きを中心にまとめます。
※ 学習用に調べた内容を個人的にまとめたものです。文章は AI の補助を受けて作成しています。
Pinia=画面をまたいで共有する状態の置き場所
Pinia は、複数のコンポーネントや画面で共有したいデータを1か所に置いておく「共有の棚」のような仕組みです。Vue 3 時代の状態管理の標準で、以前使われていた Vuex の後継にあたります。棚に置いたデータはどの画面からでも読み書きでき、変更すれば参照している画面すべてに反映されます(リアクティブ)。
共有したくなる代表例はこのあたりです。
- ログイン中のユーザー情報
- 認証トークン
- アプリ全体で使う設定(テーマ・言語など)
- 買い物カゴの中身
いつ使う/使わないの切り分け
ここが一番大事です。1つの画面(コンポーネント)の中だけで完結する状態は、Pinia に入れず ref / reactive で十分。共有が必要になって初めて Pinia を使います。
| 状態の使われ方 | 置き場所 |
|---|---|
| 1つの画面の中だけで使う(入力中の文字、開閉フラグ) | ref / reactive |
| 複数の画面・離れた部品で共有する(ログイン情報、カート) | Pinia |
最初から何でも Pinia に入れると、かえって見通しが悪くなります。「props のバケツリレーがつらくなってきた」「離れた画面で同じ値を使いたい」と感じたら Pinia、という順番がちょうどよいです。
ストアを作る
defineStore で「棚」を1つ定義します。<script setup> と同じ書き方で、状態と処理をまとめられます(セットアップストア形式)。
// src/stores/authStore.ts
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useAuthStore = defineStore('auth', () => {
const user = ref<{ name: string } | null>(null)
const isLoggedIn = computed(() => user.value !== null)
function login(name: string) {
user.value = { name }
}
function logout() {
user.value = null
}
return { user, isLoggedIn, login, logout }
})
画面から使う
使いたいコンポーネントで useAuthStore() を呼ぶだけ。別の画面で login() した結果が、こちらの表示にも反映されます。
<script setup lang="ts">
import { useAuthStore } from '@/stores/authStore'
const auth = useAuthStore()
</script>
<template>
<p v-if="auth.isLoggedIn">こんにちは、{{ auth.user?.name }} さん</p>
<button @click="auth.logout()">ログアウト</button>
</template>
main.ts で app.use(createPinia()) を一度だけ登録しておけば、どの画面からでもこの棚にアクセスできます。「共有すべき状態だけを Pinia に、それ以外は各コンポーネントに」——この線引きさえ守れば、状態管理はぐっと扱いやすくなります。
もっと体系的に学ぶなら(書籍)
この記事はシリーズの一部です。TypeScript前提で Composition API・Pinia・Vue Router・テストまで一冊で体系的に学びたい方には、内容がそのまま重なる次の本がおすすめです。
PR
📕 紙の本
Vue 3 フロントエンド開発の教科書 [ WINGSプロジェクト 齊藤 新三 ] 価格:3960円 |
📱 電子書籍版
Vue 3 フロントエンド開発の教科書 【電子書籍】[ WINGSプロジェクト 齊藤新三【著】 ] 価格:3960円 |
次に読む



