前言#
もう何年も経っているのに、まだ伝統的な状態管理ライブラリを使っているのですか?さあ、Pinia
を学びましょう!
Pinia という名前の由来も面白いです。スペイン語で、Pinia はパイナップルという言葉の最も似た英語の発音です。そして、パイナップルは一組の個別の花が結合してできたもので、複数の果物を生み出します。これは stores に似ていて、それぞれが独立していますが、最終的にはつながりがあります。
私たちがvuex
の github リポジトリを開くと、公式のメッセージPinia is now the new defaultが表示されます。Vue の次世代公式状態管理ライブラリとして、Pinia は多くの利点を持ち、Vuex が残した多くの問題を解決しています。書く際には、より論理的になります。それでは、少し理解してみましょう!
Pinia の利点#
- vue3 と vue2 の両方をサポート
- Mutation の操作を廃止し、
state
、getter
、action
のみ Actions
は同期と非同期をサポート- プラグインを使用して Pinia の機能を拡張可能
- モジュールのネストが不要で、Vue3 の
Composition api
により適合 - TypeScript をサポート
- コードがより簡潔
Pinia 方式でストアを作成#
まず、空のプロジェクトを素早く作成し、Pinia
をインストールします:
npm install pinia
Pinia は vue2 をサポートしていますが、使用している vue のバージョンがVue2.7
未満の場合は、composition api を独立してインストールする必要があります:@vue/composition-api
(ここでは直接 Vue2.7 にアップグレードすることをお勧めします。Vue3 に比べて大きな違いはなく、Vue のエコシステムのサポートがより良くなります)
main.ts
で Pinia をインポートします:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
次に、src/store
にcounter.ts
を作成し、基本テンプレートを書きます:
import { defineStore } from "pinia";
export const mainStore = defineStore('main', {
state: () => {
return {
helloWord: 'HelloWorld'
}
},
getters: {
},
actions: {
}
})
mainStore(ストア名)
を作成した後、コンポーネントで使用します。
<template>
<div class="">{{ store.helloWord }}</div>
</template>
<script lang="ts" setup>
import { mainStore } from "../store/counter";
const store = mainStore();
</script>
<style scoped></style>
ページにhelloWorld
が表示されれば、store
が正常に作成されたことを示します。
Pinia でデータ状態を変更#
counter.ts
のstate
にデータcount
を追加します:
import { defineStore } from "pinia";
export const mainStore = defineStore('main', {
state: () => {
return {
count: 0,
helloWord: 'HelloWorld'
}
},
getters: {
},
actions: {
}
})
クリックイベント
ボタンを作成します:
<template>
<div>
<button @click="handleClick">データ状態を変更</button>
</div>
</template>
<script setup lang="ts">
import { mainStore } from "@/stores/counter";
const store = mainStore();
const handleClick = () => {
store.count++;
};
</script>
これをApp.vue
にインポートし、データ状態を変更します:
<template>
<Click />
<CountButton />
</template>
<script lang="ts" setup>
import Click from "./components/Click.vue";
import CountButton from "./components/CountButton.vue";
</script>
この時、ボタンをクリックするとcount
の値が変更されることがわかります。
実際の開発では、storeのデータ
を何度も呼び出す必要があることが多いです。毎回その値を変更するために{{store.****}}
を使うのは面倒なので、解構します:
<template>
<div class="">{{ store.helloWord }}</div>
<div class="">{{ store.count }}</div>
<hr />
<!-- 解構後はstoreを省略でき、コード量が減ります -->
<div>{{ helloWord }}</div>
<div>{{ count }}</div>
</template>
<script lang="ts" setup>
import { mainStore } from "../store/counter";
import { storeToRefs } from "pinia";
const store = mainStore();
// 解構を行う
const { helloWord, count } = storeToRefs(store);
</script>
<style scoped></style>
注意:解構にはstoreToRefs()
関数を使用する必要があります!
Pinia でデータを変更する 4 つの方法#
- 第一の方法:
const handleClick = () => {
store.count++;
};
- 第二の方法
$patch
const handleClickPatch=()=>{
store.$patch({
count:store.count+2
})
}
第二の方法は第一の方法ほど簡単ではありませんが、複数のデータ
の変更により適しています。
- 第三の方法
$patchに関数を渡す
const handleClickMethod = () => {
// ここでのstateはストアのstateを指します
store.$patch((state) => {
state.count++;
state.helloWord = state.helloWord === "jspang" ? "Hello World" : "jspang";
});
};
- 第四の方法
action
ビジネスロジックが非常に複雑な場合は、メソッドをstore
のaction
に書きます。
actions: {
changeState() {
this.count++
this.helloWord = 'jspang'
}
}
Getters#
vuex の getters とほぼ同じで、vue の計算プロパティに相当します。しかし、vuex のドキュメントを確認すると、次のような注意書きがあります:
注意
Vue 3.0 以降、getter の結果は計算プロパティのようにキャッシュされなくなりました。これは既知の問題で、3.1 バージョンで修正される予定です。詳細は PR #1878をご覧ください。
今でもこの注意書きは存在しており、これが私がPinia
を使用することをより推奨する理由の一つです。
Pinia のGetters
は内部でキャッシュが可能であることをコードで確認します:
getters: {
phoneHidden(state) {
// 正規表現
console.log('gettersが呼び出されました');
return state.phone.toString().replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')
}
},
コンポーネント内で phone(データ)を 2 回呼び出し、コンソールを開いて確認します。
1 回だけ表示されることが確認でき、キャッシュ機能があることが証明されました。これはパフォーマンスの最適化
に役立ちます。
Pinia の stores 相互呼び出し#
実際の開発では、通常 1 つのストアだけを使用することはありません。ストア同士は通常、調整があります。ここで新しいストアを作成します:
import { defineStore } from "pinia";
export const nameStore = defineStore('name', {
state: () => {
return {
list: ['小紅', '小美', '胖丫']
}
}
})
次に、counter.ts
にインポートし、import {jspangStore} from './jspang'
を行い、action
内で呼び出します:
actions: {
getList() {
console.log(nameStore().list);
}
}
コンソールを確認すると、別のストアのstate
を正常に呼び出すことができ、store
間の相互呼び出しが成功しました。
VueDevtools をサポート#
Pinia は新人ですが、すでに VueDevtools を全面的にサポートしています。これは実際のプロジェクト開発におけるデバッグに大いに役立ちます。特に、VueDevtools を開くと、非常に可愛らしいパイナップルのロゴが見えます!
開発中の気分も良くなりますね、ハハハ。
注意:Pinia v2 を使用している場合は、
Vue Devtools
を v6 バージョンにアップグレードしてください。
Pinia 実践:アバターを変更#
これまでの説明を踏まえ、実際のプロジェクトでpinia
を活用してみましょう。開発の背景:ウェブページを作成する際、登録機能
が関与することが多く、ユーザーのアバターはログイン前
とログイン後
で異なります。アバターを変更するためにクリックイベントを 1 つだけ作成すると、ページをリフレッシュしたり移動したりすると元に戻ってしまい、状態が保存されません。この時、私たちの pinia を活用できます。
注意:pinia のデータを永続的に保存するため(localstorage または sessionstorage に保存するため)、プラグインをインストールする必要があります:pinia-plugin-persist。これにより、操作がより便利になります。詳細は公式文書を参照してください。
1. ストアを作成#
最初のステップはストアを作成する
ことです(ここでは関連環境がすでに設定されていることを前提としています)。store/user.ts
を作成し、具体的なコードは以下の通りです:
import { defineStore } from 'pinia';
export const mainStore = defineStore('main', {
state: () => {
return {
login: require('../assets/images/login.png')
}
},
// 永続化を有効にする
persist: {
enabled: true,
strategies: [
{ storage: localStorage, paths: ['login'] }
],
},
getters: {
},
actions: {
}
})
成功裏に作成した後、ユーザーアバター
をストア
に保存しました。次は、コンポーネントでそれを使用します。
2. コンポーネントで呼び出す#
<!-- アバター -->
<a class="face" href="#/login">
<img :src="store.login" alt="" />
</a>
ブラウザを開いて確認します:
成功裏に呼び出しました!次は最も重要なステップです。ログイン後にアバターが正常にローカルに保存されるようにします。この時、直接actions
にデータを変更する操作を追加します:
actions: {
changeHeadShot() {
console.log('データが正常に保存されました');
this.login = require('../assets/images/head.png')
}
}
作成したaction
をコンポーネントで使用します:
<template>
<!-- 不要なコードを省略 (ここではvantのコンポーネントを使用しています)-->
<van-col span="8" @click="headerC">
<van-button class="btn2" plain hairlin type="primary" to="/">
<p class="text">ログイン</p>
</van-button>
</van-col>
</template>
<script setup>
//ストアをインポート
import { mainStore } from '@/store/user'
const login = mainStore()
//アバターを変更する関数を実装
function headerC() {
login.changeHeadShot()
}
</script>
<style scoped>
/* 不要なコードを省略 */
</style>
次は「奇跡を目撃する」時です:ログインボタンをクリックすると、アバターが変更されます:
この時、どんなにリフレッシュしても、アバターは変わりません。コンソールを開いてアプリケーションのストレージ
を確認すると、ログインアバターがローカルのブラウザに保存されていることがわかります:
結語#
要するに、あなたが以前に Vuex に触れたことがあるかどうかにかかわらず、私はPinia
の使用を強くお勧めします。Vuex に比べて、より良い互換性を持ち、Vuex の基盤の上にMutation
を取り除き、文法をより簡潔にし、Vue3 のComposition api
により適合しています。Vuex はもはや更新されず、現在はメンテナンス状態にありますが、Pinia は次世代の Vuex として、学び、使用しない理由は何もありません。