1.ピニアの紹介
- Pinia は、コンポーネントまたはページ間で状態を共有できる Vue 固有の状態管理ライブラリです。
- Pinia は、Vuex の次のイテレーションを調査するための実験として開始されたため、Vuex 5 コア チームの議論から多くのアイデアが組み込まれています。
mutation
廃止されました。多くの場合、それらは非常に冗長であると見なされます。彼らの当初の意図は、devtools 統合ソリューションを提供することでしたが、これはもはや問題ではありません。
Vuex 3.x 只适配 Vue 2,而 Vuex 4.x 是适配 Vue 3 的。
- 非常に軽量: Pinia のサイズはわずか約 1kb です。
- 開発ツールのサポート: Vue 2 であろうと Vue 3 であろうと、Vue devtools フックをサポートする Pinia は、より優れた開発エクスペリエンスを提供します。
- Type-safe : 型は自動的に推測され、JavaScript でもオートコンプリートが提供されます!
- Pinia は、2019 年 11 月頃に構成 API を使用して Vue 状態管理ライブラリを設計する実験として開始されました。
- それ以来、Vue 2 と Vue 3 の両方をサポートする傾向があり、開発者はコンポジション API の使用を強制されていません。
2. 基本例
- pinia API の基本的な使い方は以下のとおりです。
- 最初にストアを作成できます。
import {
defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return {
count: 0 }
},
actions: {
increment() {
this.count++
},
},
})
- より高度な使い方として、関数 (コンポーネントの setup() と同様) を使用して Store を定義することもできます。
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return {
count, increment }
})
import {
useCounterStore } from '@/stores/counter'
export default {
setup() {
const counter = useCounterStore()
counter.count++
counter.$patch({
count: counter.count + 1 })
counter.increment()
},
}
- setup() 関数と合成 API に慣れていない場合、Pinia は、mapStores()、mapState()、または mapActions() を通じてアクセスされる、Vuex のマッピング状態に似た一連の補助関数も提供します。
export default {
computed: {
...mapStores(useCounterStore, useUserStore)
...mapState(useCounterStore, ['count', 'double']),
},
methods: {
...mapActions(useCounterStore, ['increment']),
},
}
import {
useCounterStore } from '@/stores/counter'
function xxxx = () =>{
const counter = useCounterStore()
counter.count++
counter.increment()
}
3. コアコンセプト
1.ストアを定義する
- Store は defineStore() で定義されており、その最初のパラメーターには一意の名前が必要であることを知っておく必要があります。
import {
defineStore } from 'pinia'
export const useStore = defineStore('main', {
})
- ID としても使用されるこのname は必須であり、Pinia はそれを使用してストアを devtools に接続します。
defineStore()
の 2 番目のパラメーターは、Setup 関数または Option オブジェクトの 2 種類の値を受け入れます。
- Vue のオプション API と同様に、状態、アクション、およびゲッター プロパティを持つ Option オブジェクトを渡すこともできます。
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0 }),
getters: {
double: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
})
- Vue コンポジション API の setup 関数と同様に、リアクティブなプロパティとメソッドを定義する関数を渡し、公開したいプロパティとメソッドを含むオブジェクトを返すことができます。
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return {
count, increment }
})
- セットアップ ストア:
ref() 就是 state 属性、computed() 就是 getters、function() 就是 actions
- セットアップ ストアは、ストア内にリスナーを作成し、任意の構成機能を自由に使用できるため、オプション ストアよりも柔軟性があります。
2、状態
- ほとんどの場合、状態はストアの中心です。
- 通常、アプリを表す状態を定義することから始めます。
- Pinia では、state は初期状態を返す関数として定義されています。これにより、Pinia はサーバーとクライアントの両方をサポートできます。
import {
defineStore } from 'pinia'
const useStore = defineStore('storeId', {
state: () => {
return {
count: 0,
name: 'Eduardo',
isAdmin: true,
items: [],
hasChanged: true,
}
},
})
默认情况下,你可以通过 store 实例访问 state,直接对其进行读写。
const store = useStore()
store.count++
可以通过调用 store 的 $reset() 方法将 state 重置为初始值。
const store = useStore()
store.$reset()
除了用 store.count++ 直接改变 store,你还可以调用 $patch 方法。它允许你用一个 state 的补丁对象在同一时间更改多个属性:
store.$patch({
count: store.count + 1,
age: 120,
name: 'DIO',
})
$patch 方法也接受一个函数来组合这种难以用补丁对象实现的变更。
store.$patch((state) => {
state.items.push({
name: 'shoes', quantity: 1 })
state.hasChanged = true
})
你不能完全替换掉 store 的 state,因为那样会破坏其响应性。但是,你可以 patch 它。
store.$state = {
count: 24 }
store.$patch({
count: 24 })
3、ゲッター
- getter は、ストアの状態の計算値とまったく同じです。
- これらは、defineStore() の getters プロパティを介して定義できます。アロー関数が推奨され、最初の引数として状態を受け取ります。
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
getters: {
doubleCount: (state) => state.count * 2,
},
})
- ほとんどの場合、ゲッターは状態のみに依存しますが、他のゲッターも使用する場合があります。
- したがって、通常の関数でゲッターを定義する場合でも、これを介してストア インスタンス全体にアクセスできます。
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
getters: {
doubleCount(state) {
return state.count * 2
},
doublePlusOne(): number {
return this.doubleCount + 1
},
},
})
- 次に、ストア インスタンスのゲッターに直接アクセスできます。
<template>
<p>Double count is {
{
store.doubleCount }}</p>
</template>
<script>
export default {
setup() {
const store = useStore()
return {
store }
},
}
</script>
4、アクション
- アクションはコンポーネントのメソッドに相当します。
- これらは defineStore() の actions 属性を介して定義でき、ビジネス ロジックの定義にも最適です。
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++
},
randomizeCounter() {
this.count = Math.round(100 * Math.random())
},
},
})
- ゲッターと同様に、アクションはこれを介してストア インスタンス全体にアクセスすることもでき、完全な型注釈 (およびオートコンプリート ✨) をサポートします。
- 違いは、アクションは非同期にすることができ、await を使用して任意の API を呼び出すことができ、他のアクションも実行できることです!
import {
mande } from 'mande'
const api = mande('/api/users')
export const useUsers = defineStore('users', {
state: () => ({
userData: null,
}),
actions: {
async registerUser(login, password) {
try {
this.userData = await api.post({
login, password })
showTooltip(`Welcome back ${
this.userData.name}!`)
} catch (error) {
showTooltip(error)
return error
}
},
},
})
- アクションはメソッドのように呼び出すことができます:
export default defineComponent({
setup() {
const main = useMainStore()
main.randomizeCounter()
return {
}
},
})
- 別のストアを使用する場合は、アクションで直接呼び出すことができます。
import {
useAuthStore } from './auth-store'
export const useSettingsStore = defineStore('settings', {
state: () => ({
preferences: null,
}),
actions: {
async fetchUserPreferences() {
const auth = useAuthStore()
if (auth.isAuthenticated) {
this.preferences = await fetchPreferences()
} else {
throw new Error('User must be authenticated')
}
},
},
})