Vue 3 の状態管理ライブラリ「Pinia」を初心者向けに解説!

その他

はじめに

Vue.js でアプリを作ると、コンポーネント同士でデータを共有することが増えてきます。
小規模なら propsemit で対応できますが、大規模になると管理が複雑になります。
そこで役立つのが Pinia(ピニャ) という 状態管理ライブラリ です!

本記事では、Pinia の基本概念・使い方・実践例 まで、初心者向けにわかりやすく解説します!

Pinia とは?

状態管理とは?

Vue.js では、コンポーネントごとにデータ(data())を管理できますが、複数のコンポーネントでデータを共有 しようとすると、propsemit でのやり取りが増えて 管理が大変 になります。

Pinia を使うメリット

  • 状態(データ)を一元管理 → どのコンポーネントからでもアクセス可能
  • Vuex よりシンプルで使いやすい
  • TypeScript との相性が良い
  • 非同期処理も簡単に管理できる

Pinia のストアの概念と基本的な使い方

Pinia の 3 つの主要機能

機能役割
stateアプリ全体のデータ(状態)を管理
actionsstate を変更する関数(同期・非同期)
gettersstate を加工して取得

Pinia ストアの構成

import { defineStore } from "pinia";

export const useCounterStore = defineStore("counter", {
  state: () => ({ count: 0 }),
  actions: {
    increment() { this.count++ },
    async asyncIncrement() { setTimeout(() => { this.increment() }, 1000) }
  },
  getters: {
    doubleCount: state => state.count * 2
  }
});

Pinia をプロジェクトに導入する方法

Vue CLI や Vite を使っている場合、以下のコマンドで Pinia をインストールできます。

npm install pinia

Pinia を 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");

これでアプリ全体で store が使えるようになります!

state を使ったデータ管理

state はアプリ全体のデータを保存する場所です。

カウントの state を定義

import { defineStore } from "pinia";

export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0
  })
});
  • 第一引数のcounterはストアを一意に識別するための名前です。

コンポーネントで state を使用

<template>
  <p>カウント: {{ store.count }}</p>
</template>

<script setup>
import { useCounterStore } from "@/stores/counter";

const store = useCounterStore();
</script>

store.count にアクセスすることで、アプリのどこからでもデータを取得可能!

actions で state を変更

actionsstate を変更するための関数です。

カウントを増やす actions

export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++;
    }
  }
});

コンポーネントで actions を呼び出し

<template>
  <button @click="store.increment">増やす</button>
</template>

<script setup>
import { useCounterStore } from "@/stores/counter";

const store = useCounterStore();
</script>

ボタンをクリックすると store.increment()state.count が増える!

actions で非同期処理を管理

actions を使うと API 取得や setTimeout を使った非同期処理 を実装できます。

actions で非同期処理を追加

export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0
  }),
  actions: {
    async asyncIncrement() {
      setTimeout(() => {
        this.increment();
      }, 1000);
    }
  }
});

コンポーネントで actions を呼び出し

<template>
  <button @click="store.asyncIncrement">1秒後に増やす</button>
</template>

<script setup>
import { useCounterStore } from "@/stores/counter";

const store = useCounterStore();
</script>

ボタンをクリックすると 1 秒後に state.count が増える!

getters で state を加工して取得

gettersstate のデータを 計算して取得 できます。

state.count を 2 倍にする getters

export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0
  }),
  getters: {
    doubleCount: state => state.count * 2
  }
});

コンポーネントで getters を使用

<template>
  <p>2倍のカウント: {{ store.doubleCount }}</p>
</template>

<script setup>
import { useCounterStore } from "@/stores/counter";

const store = useCounterStore();
</script>

リアルタイムで計算された値を取得可能!

Pinia の実践例(カウンターアプリ)

Pinia を使ってシンプルなカウンターアプリを作成!

stores/counter.js

import { defineStore } from "pinia";

export const useCounterStore = defineStore("counter", {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() { this.count++; },
    async asyncIncrement() { setTimeout(() => { this.increment(); }, 1000); }
  },
  getters: {
    doubleCount: state => state.count * 2
  }
});

App.vue

<template>
  <p>カウント: {{ store.count }}</p>
  <p>2倍のカウント: {{ store.doubleCount }}</p>
  <button @click="store.increment">増やす</button>
  <button @click="store.asyncIncrement">1秒後に増やす</button>
</template>

<script setup>
import { useCounterStore } from "@/stores/counter";

const store = useCounterStore();
</script>

Pinia を使えば、どのコンポーネントからでも count を管理できる!

Vuex と Pinia の違い

比較項目VuexPinia
記述量多い少ない
非同期処理actionscommit を呼ぶactions 内で直接 state を変更できる
型安全性なしTypeScript に適している

まとめ

piniaの使い方(defineStoreの基本構文)は以下の通りです。

import { defineStore } from "pinia";

export const useCounterStore = defineStore(
  "counter", // ① ストアID
  {
    state: () => ({ count: 0 }), // ② ストアの状態(state)
    actions: {
      increment() {
        this.count++;
      }
    }, // ③ アクション(メソッド)
    getters: {
      doubleCount: state => state.count * 2
    } // ④ ゲッター(計算プロパティ)
  }
);
引数説明必須
idストアを識別するための名前
stateアプリの状態(データ)
actionsデータを変更する関数(同期/非同期)
gettersstate を加工して取得する関数

今後の Vue 3 開発では Pinia が主流になっていくため、ぜひ習得しましょう!

コメント

タイトルとURLをコピーしました