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`のプロパティを利用して設定することが可能である。