Piniaについて
Vue3の状態管理ツールのPiniaについてのまとめ
基本的な使い方
最初のプロジェクト作成時だとサンプルができているが、途中からインストールするには下記のコマンド。
npm install pinia
初期設定
インストールしただけでは使えないので使えるようにする。
createPiniaをインポートして、createPinia()でオブジェクトを作成してuseで指定する。
import './assets/main.css'
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
StoresでPiniaを使ってみる。
慣例的にフォルダ名をStoreとかStoresとかにするんだと思われる。今回はStoresにしてTODOを管理するファイルを作成してみる。
Storeファイルを作成する
まずはTODOを管理するためのファイルを作成する。名前はtodo.jsとしている。
import { defineStore } from "pinia";
import { ref } from "vue";
export const useTodoStore = defineStore('todos', () => {
const todos = ref(
[{
id: "",
task: ""
}]
)
const addTask = (newTask) => {
todos.value.push(newTask)
}
return { todos, addTask }
})
簡単なテストとして、リアクティブなtodosという変数を用意。
タスク自体はオブジェクトとして{id:String,task:String}としてIDは登録した日付にする。
addTask関数でこのtodosに追加する処理を設定して、todosとaddTaskをreturnしている。
TODOと追加するコンポーネントを作成する
フォームとしてTaskFrom.vueというファイルをcomponentsフォルダ配下に作成する。
<template>
<form @submit.prevent="inputHandler">
<input type="text" v-model="inputRef" />
<button type="submit">追加</button>
</form>
</template>
<script setup>
import { useTodoStore } from '@/stores/todos';
import { ref } from 'vue';
const todoStore = useTodoStore()
const inputRef = ref("")
const inputHandler = () => {
const trimmedValue = inputRef.value.trim();
// 入力値が空の場合
if (trimmedValue === '') {
alert('入力値が空です。処理を中断します。');
return;
}
let task = {
id: new Date().getTime(),
task: trimmedValue
}
todoStore.addTask(task)
}
</script>
useTodoStore をインポートしてtodoStoreというオブジェクトを作成する。
フォームのinput要素にはリアクティブなinputRef という変数を設定する。
その値を元に、スペースを削除して空白だった場合はアラート表示させている。
あとはidは現在の時間を取得して設定して、taskは入力した値を設定してtodoStore.addTask()に渡している。これでtodo.jsで設定したtodosというリアクティブな値の配列に保存されている。
これを別のコンポーネントで追加したTODOを一覧表示されていれば成功となる。
別のコンポーネントで一覧を表示してみる。
先ほどのTaskForm.vueでuseTodoStoreの処理を行ったので、今度は追加されたら一覧に自動的に反映されるかどうかを別のコンポーネントから表示させてみる。
App.vueでもどこでもいいですが、デフォルトであったHomeView.vueで試してみる。
あとHomeView.vueでタスクの追加のフォームを表示させたいので、TaskForm.vueのコンポーネントも読み込んでます。
<script setup>
import TaskFrom from '@/components/TaskFrom.vue';
import { useTodoStore } from '@/stores/todos';
import { storeToRefs } from 'pinia';
const todoStore=useTodoStore()
const {todos} = storeToRefs(todoStore)
</script>
<template>
<main>
<TaskFrom />
<ul>
<li v-for="todo in todos" :key="todo.id">
{{ todo.task }}
</li>
</ul>
</main>
</template>
これまでと同じようにuseTodoStoreをインポートして、todoStoreというオブジェクトを読み込んでいる。
また一覧表示させたいのでtodosを分割代入で読み込んでいるが、注意が必要。
分割代入するとリアクティブではなくなるので、toRefsではなくstoreToRefsを使用すること。
あとは通常のv-forでループ処理すれば保存されたタスクが表示されるはず。
永続化について
さすがに状態管理のPiniaといえども、リロードするとデータが消えるんですね。
それだと困るという場合はpinia-plugin-persistedstateというプラグインを追加する。
プラグインのインストールと初期設定
npm install pinia-plugin-persistedstate
プラグインをインストールしたら永続化したいストアに設定する。
そしたら、main.jsで使えるようにする。以下必要な処理だけ記載。
import { createPinia } from 'pinia'
import {createPersistedState} from 'pinia-plugin-persistedstate' //追加
const app = createApp(App)
const pinia = createPinia();
pinia.use(createPersistedState()); // 追加
app.use(pinia)
使いたいストアでの永続化
どのストアを永続化したいか。まずはプロジェクト作成時にPiniaをインストールするとデフォルトであるcounter.jsのストアで設定してみる。
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 }
},
{
persist:true
}
)
defineStoreの第3引数にpersisitというプロパティがあるのでこちらをtrueすることで永続化ができる。
永続化とは
永続化とはその詳細はlocalStrageである。上記の設定はlocalStorageだが、sessinoStorageを使いたい場合は以下の設定になる。
{
persist: {
storage: persistedState.sessionStorage,
},
}
これでsessionStorageが使えるようになる。
Piniaの別の書き方について
これまでは関数のように記載していましたが、以下のように書くことも可能。
import { defineStore } from "pinia";
export const useTestCounterStore = defineStore("counter", {
state: () => ({
count: 0
}),
actions: {
increment() {
this.count++;
},
},
getters: {
doubleCount() {
return this.count * 2;
},
},
});
`state`, `actions`, `getters`のプロパティを利用して設定することが可能である。