大家好,我是 V 哥。Pinia 是 Vue 的狀態(tài)管理庫,它提供了一種更簡(jiǎn)單、更不規(guī)范的 API 來管理應(yīng)用的狀態(tài)。Pinia 的設(shè)計(jì)哲學(xué)是簡(jiǎn)單性和易用性,它避免了 Vuex 中的許多復(fù)雜概念,如 mutations 和模塊的嵌套結(jié)構(gòu),提供了一種更現(xiàn)代、更符合 Vue 3 Composition API 風(fēng)格的狀態(tài)管理方式。
先來瞅一眼 Pinia 的核心組件主要包括以下幾個(gè)方面:
下面是每個(gè)部分的詳細(xì)介紹。
在 Pinia 中,Store
是用來封裝應(yīng)用的狀態(tài)和邏輯的核心概念。它允許你將狀態(tài)和行為集中管理,而不是分散在各個(gè)組件中。Store
可以包含以下幾部分:
下面是一個(gè)創(chuàng)建 Store
的步驟解析,包括代碼示例:
首先,你需要從 Pinia 導(dǎo)入 defineStore
函數(shù),并使用它來定義一個(gè)新的 Store
。
import { defineStore } from 'pinia'
export const useUserStore = defineStore('user', {
state: () => ({
users: [] // 初始狀態(tài)是一個(gè)空數(shù)組
}),
getters: {
// 一個(gè) getter 函數(shù),返回?cái)?shù)組中的用戶數(shù)量
count: (state) => state.users.length
},
actions: {
// 一個(gè) action 函數(shù),用于添加用戶
addUser(user) {
this.users.push(user)
}
}
})
在 Vue 組件中,你可以通過調(diào)用你定義的 useUserStore
函數(shù)來使用這個(gè) Store
。
<template>
<div>
<button @click="addNewUser">添加用戶</button>
<p>用戶總數(shù): {{ userCount }}</p>
<ul>
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useUserStore from '@/stores/user'
const store = useUserStore()
const users = computed(() => store.users)
const userCount = computed(() => store.count)
function addNewUser() {
store.addUser({ id: Date.now(), name: '新用戶' })
}
</script>
defineStore
:從 Pinia 導(dǎo)入 defineStore
函數(shù)來定義新的 Store
。useUserStore
:創(chuàng)建一個(gè)名為 useUserStore
的函數(shù),它返回一個(gè) Store
對(duì)象。Store
中定義了一個(gè)狀態(tài) users
,初始為空數(shù)組。count
getter,它返回 users
數(shù)組的長(zhǎng)度。addUser
action,它接受一個(gè)用戶對(duì)象并將其添加到 users
數(shù)組中。<script setup>
塊中,通過調(diào)用 useUserStore
來獲取 Store
實(shí)例,并使用 computed
來創(chuàng)建響應(yīng)式的 users
和 userCount
。addNewUser
函數(shù),當(dāng)按鈕被點(diǎn)擊時(shí),調(diào)用 store.addUser
來添加新用戶。
以上案例展示了如何在 Pinia 中創(chuàng)建和管理狀態(tài),以及如何在 Vue 組件中使用 Store
。通過這種方式,你可以集中管理狀態(tài),使得狀態(tài)邏輯更加清晰和可維護(hù)。
defineStore()
是 Pinia 中用于定義 Store 的函數(shù)。它允許你以聲明式的方式創(chuàng)建一個(gè)狀態(tài)管理單元,這個(gè)單元可以包含狀態(tài)(state)、獲取器(getters)、動(dòng)作(actions)等。defineStore()
函數(shù)接受一個(gè)唯一的 ID 和一個(gè)配置對(duì)象,配置對(duì)象中可以定義 state、getters、actions 等屬性。
下面是一個(gè)使用 defineStore()
創(chuàng)建 Store 的步驟解析,包括代碼示例:
首先,需要從 Pinia 導(dǎo)入 defineStore
函數(shù)。
import { defineStore } from 'pinia'
使用 defineStore()
定義一個(gè)新的 Store,傳入一個(gè)唯一的 ID 和一個(gè)配置對(duì)象。
export const useCartStore = defineStore('cart', {
state: () => ({
items: [] // 購物車初始狀態(tài)為空數(shù)組
}),
getters: {
// 計(jì)算屬性,返回購物車中商品的總數(shù)量
itemCount(state) {
return state.items.reduce((total, item) => total + item.quantity, 0)
}
},
actions: {
// 添加商品到購物車的動(dòng)作
addItem(item) {
const index = this.items.findIndex(i => i.id === item.id)
if (index > -1) {
// 如果商品已存在,則增加數(shù)量
this.items[index].quantity += item.quantity
} else {
// 否則,添加新商品
this.items.push(item)
}
},
// 清空購物車的動(dòng)作
clearCart() {
this.items = []
}
}
})
在 Vue 組件中,通過調(diào)用 useCartStore
來使用這個(gè) Store。
<template>
<div>
<button @click="addItem">添加商品</button>
<button @click="clearCart">清空購物車</button>
<p>商品總數(shù): {{ itemCount }}</p>
<ul>
<li v-for="item in cartItems" :key="item.id">
{{ item.name }} - 數(shù)量: {{ item.quantity }}
</li>
</ul>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useCartStore from '@/stores/cart'
const store = useCartStore()
const cartItems = computed(() => store.items)
const itemCount = computed(() => store.itemCount)
function addItem() {
store.addItem({ id: 1, name: '商品A', quantity: 1 })
}
function clearCart() {
store.clearCart()
}
</script>
defineStore
函數(shù)。useCartStore
的函數(shù),它返回一個(gè)配置好的 Store
對(duì)象。Store
中定義了一個(gè)狀態(tài) items
,初始為空數(shù)組,用于存儲(chǔ)購物車中的商品。itemCount
getter,它通過遍歷 items
數(shù)組并累加每個(gè)商品的 quantity
來計(jì)算總數(shù)量。addItem
和 clearCart
兩個(gè) actions。addItem
用于向購物車添加商品,如果商品已存在則增加其數(shù)量;clearCart
用于清空購物車。<script setup>
塊中,通過調(diào)用 useCartStore
來獲取 Store
實(shí)例,并使用 computed
來創(chuàng)建響應(yīng)式的 cartItems
和 itemCount
。addItem
和 clearCart
函數(shù),分別用于添加商品和清空購物車。
使用 defineStore()
創(chuàng)建一個(gè)包含狀態(tài)、獲取器和動(dòng)作的 Store,并在 Vue 組件中使用這個(gè) Store 來管理購物車的狀態(tài)。通過這種方式,你可以將狀態(tài)邏輯封裝在 Store 中,使得組件更加簡(jiǎn)潔和易于管理。
reactive()
是 Vue 3 的 Composition API 中的一個(gè)函數(shù),它用于創(chuàng)建響應(yīng)式的狀態(tài)對(duì)象。當(dāng)使用 reactive()
創(chuàng)建一個(gè)對(duì)象后,Vue 會(huì)追蹤這個(gè)對(duì)象中屬性的讀取和修改,并且在數(shù)據(jù)變化時(shí)通知依賴于這些數(shù)據(jù)的組件重新渲染。
Pinia 與 Vue 的響應(yīng)式系統(tǒng)緊密集成,reactive()
通常在定義 Store 的狀態(tài)時(shí)使用。在 Pinia 中,狀態(tài)(state)是一個(gè)通過 reactive()
創(chuàng)建的響應(yīng)式對(duì)象,因此任何對(duì)狀態(tài)的修改都會(huì)自動(dòng)觸發(fā)與該狀態(tài)相關(guān)的組件更新。
下面是一個(gè)使用 reactive()
來創(chuàng)建響應(yīng)式狀態(tài)的步驟解析:
首先,需要從 Vue 導(dǎo)入 reactive
函數(shù)。
import { reactive } from 'vue'
使用 reactive()
函數(shù)來創(chuàng)建一個(gè)響應(yīng)式的狀態(tài)對(duì)象。
const state = reactive({
count: 0, // 初始狀態(tài)
message: 'Hello, Pinia!' // 初始消息
})
在 Pinia 的 defineStore()
中,可以直接使用 reactive()
來定義狀態(tài)。
import { defineStore } from 'pinia'
import { reactive } from 'vue'
export const useMyStore = defineStore('myStore', {
state: () => reactive({
count: 0,
message: 'Hello, Pinia!'
}),
// 其他 getters 和 actions 可以在這里定義
})
在 Vue 組件中,通過調(diào)用 useMyStore
來使用這個(gè) Store,并訪問響應(yīng)式狀態(tài)。
<template>
<div>
<p>Count: {{ count }}</p>
<p>Message: {{ message }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useMyStore from '@/stores/myStore'
const store = useMyStore()
const count = computed(() => store.state.count)
const message = computed(() => store.state.message)
function increment() {
store.state.count++
}
</script>
reactive
函數(shù)。reactive()
創(chuàng)建一個(gè)包含 count
和 message
的響應(yīng)式狀態(tài)對(duì)象。defineStore()
的 state
函數(shù)中返回一個(gè) reactive()
對(duì)象,這樣 Pinia 就可以管理這個(gè)狀態(tài)的響應(yīng)性。<script setup>
塊中,通過調(diào)用 useMyStore
來獲取 Store
實(shí)例。使用 computed
來確保訪問狀態(tài)時(shí)保持響應(yīng)性。increment
函數(shù),當(dāng)按鈕被點(diǎn)擊時(shí),直接修改 store.state.count
,這會(huì)觸發(fā)組件的更新。通過這種方式,你可以確保狀態(tài)的任何變化都會(huì)自動(dòng)傳播到使用這些狀態(tài)的組件中,實(shí)現(xiàn)響應(yīng)式的數(shù)據(jù)流,你get到了嗎。
Vue Devtools 是一個(gè)瀏覽器擴(kuò)展,它為開發(fā) Vue 應(yīng)用提供了強(qiáng)大的調(diào)試支持。對(duì)于 Pinia 來說,Devtools 支持意味著你可以在開發(fā)過程中更直觀地查看和操作應(yīng)用的狀態(tài)。
Pinia 與 Vue Devtools 集成,提供了以下功能:
要充分利用 Pinia 的 Devtools 支持,你需要確保正確安裝和配置了 Vue Devtools,并且正確地在你的 Pinia Store 中編寫代碼。來吧,一步一步跟著做就行:
首先,確保你已經(jīng)安裝了 Vue Devtools 瀏覽器擴(kuò)展。你可以從 Chrome Web Store 或 Firefox Add-ons 等地方安裝。
創(chuàng)建一個(gè) Pinia Store,并定義 state、getters 和 actions。
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
在你的 Vue 應(yīng)用中創(chuàng)建 Pinia 實(shí)例,并在應(yīng)用啟動(dòng)時(shí)使用它。
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
在組件中使用你的 Store,并執(zhí)行一些狀態(tài)更改的動(dòng)作。
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useCounterStore from '@/stores/counter'
const store = useCounterStore()
const count = computed(() => store.count)
function increment() {
store.increment()
}
</script>
defineStore
創(chuàng)建一個(gè)包含 state、getters 和 actions 的 Pinia Store。利用 Vue Devtools 提供的功能來調(diào)試使用 Pinia 管理狀態(tài)的 Vue 應(yīng)用,感覺是不是挺爽。
Pinia 的插件系統(tǒng)允許開發(fā)者擴(kuò)展 Pinia 的功能。插件可以訪問 Pinia 的 Store 創(chuàng)建過程,可以執(zhí)行以下操作:
state
、getters
、actions
等屬性。Pinia 插件通常在創(chuàng)建 Pinia 實(shí)例時(shí)注冊(cè),然后 Pinia 會(huì)將插件應(yīng)用到每個(gè)創(chuàng)建的 Store 上。
下面是一個(gè)創(chuàng)建和使用 Pinia 插件的步驟解析,包括代碼示例:
首先,定義一個(gè)插件函數(shù),該函數(shù)接收 Pinia 的實(shí)例作為參數(shù)。
function myPiniaPlugin(pinia) {
// 插件邏輯
}
在插件函數(shù)內(nèi)部,可以訪問 Pinia 的 store
對(duì)象,并對(duì)其進(jìn)行操作。
function myPiniaPlugin(pinia) {
pinia.use((store) => {
// 可以在此處訪問 store.state, store.getters, store.actions 等
// 例如,向 store 添加一個(gè)新屬性
store.myCustomProperty = 'Hello from plugin!'
})
}
創(chuàng)建 Pinia 實(shí)例時(shí),使用 use
方法注冊(cè)插件。
import { createPinia } from 'pinia'
const pinia = createPinia().use(myPiniaPlugin)
定義一個(gè) Store,使用 defineStore
函數(shù)。
import { defineStore } from 'pinia'
export const useMyStore = defineStore('myStore', {
// state, getters, actions 定義
state: () => ({
value: 0
}),
// 其他選項(xiàng)...
})
在組件中使用 Store,并訪問插件添加的屬性。
<template>
<div>
<p>Value: {{ value }}</p>
<p>Plugin Property: {{ store.myCustomProperty }}</p>
</div>
</template>
<script setup>
import { computed } from 'vue'
import useMyStore from '@/stores/myStore'
const store = useMyStore()
const value = computed(() => store.value)
</script>
在組件的模板或腳本中,使用插件添加到 Store 的自定義屬性。
// 在模板中
<p>Plugin Property: {{ store.myCustomProperty }}</p>
// 在腳本中
console.log(store.myCustomProperty) // 輸出: Hello from plugin!
pinia.use
方法注冊(cè)一個(gè)回調(diào),該回調(diào)接收每個(gè) Store 并可以對(duì)其進(jìn)行操作。.use()
方法注冊(cè)插件。defineStore
定義 Store,包括 state、getters、actions。記住這一點(diǎn),開發(fā)者需要添加自定義邏輯和屬性,通過Pinia 插件系統(tǒng)就 OK。
Pinia 為 TypeScript 用戶提供了一流的支持,確保類型安全和開發(fā)體驗(yàn)。Pinia 的 TypeScript 支持主要體現(xiàn)在以下幾個(gè)方面:
.d.ts
),確保 Pinia API 在 TypeScript 項(xiàng)目中的類型正確性。下面是一個(gè)使用 TypeScript 與 Pinia 結(jié)合使用的步驟解析,包括代碼示例:
確保你的項(xiàng)目已經(jīng)配置了 TypeScript,并且安裝了必要的類型聲明文件。
npm install typescript @vue/compiler-sfc
使用 TypeScript 的類型定義來創(chuàng)建 Pinia Store。
import { defineStore } from 'pinia'
interface State {
count: number
message: string
}
export const useMyStore = defineStore('myStore', {
state: (): State => ({
count: 0,
message: 'Hello, Pinia with TypeScript!'
}),
getters: {
// 使用 TypeScript 來聲明 getter 的返回類型
doubleCount: (state): number => state.count * 2
},
actions: {
increment(): void {
this.count++
}
}
})
在 Vue 組件中使用 Store,并利用 TypeScript 提供類型安全。
<template>
<div>
<p>Count: {{ count }}</p>
<p>Message: {{ message }}</p>
<p>Double Count: {{ doubleCount }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
import useMyStore from '@/stores/myStore'
const store = useMyStore()
const count = computed(() => store.count)
const message = computed(() => store.message)
const doubleCount = computed(() => store.doubleCount)
function increment() {
store.increment()
}
</script>
使用類型守衛(wèi)來確保對(duì) Store 屬性的訪問是安全的。
if (store.hasOwnProperty('count')) {
// TypeScript 知道 'count' 存在且為 number 類型
console.log(store.count)
}
interface
)來定義 Store 的狀態(tài)類型。defineStore
并傳入類型化的 state 函數(shù),以及聲明了返回類型的 getters 和 actions。hasOwnProperty
方法和類型守衛(wèi)來安全地訪問 Store 的屬性。小結(jié)一下,Pinia 與 TypeScript 結(jié)合使用可以提供類型安全的狀態(tài)管理,同時(shí)編輯器的自動(dòng)補(bǔ)全和類型檢查功能可以提高開發(fā)效率和減少錯(cuò)誤。
服務(wù)器端渲染(SSR)是一種將網(wǎng)站頁面在服務(wù)器上生成并發(fā)送給客戶端的技術(shù)。對(duì)于狀態(tài)管理庫來說,SSR 支持意味著可以在服務(wù)器上初始化和操作狀態(tài),然后將狀態(tài)序列化后發(fā)送到客戶端,客戶端再將這些狀態(tài)恢復(fù)以保持與服務(wù)器端相同的狀態(tài)。
Pinia 對(duì) SSR 的支持主要體現(xiàn)在以下幾個(gè)方面:
下面是一個(gè)使用 Pinia 進(jìn)行 SSR 的步驟解析,包括代碼示例:
首先,定義一個(gè) Pinia Store。
import { defineStore } from 'pinia'
export const useMyStore = defineStore('myStore', {
state: () => ({
count: 0
}),
// 其他選項(xiàng)...
})
在服務(wù)器端,創(chuàng)建 Store 實(shí)例并初始化狀態(tài),然后將狀態(tài)序列化。
// server.js
import { createPinia } from 'pinia'
import useMyStore from '@/stores/myStore'
const pinia = createPinia()
// 模擬從數(shù)據(jù)庫獲取初始狀態(tài)
const initialState = { count: 10 }
// 創(chuàng)建 Store 實(shí)例并設(shè)置初始狀態(tài)
const store = useMyStore(pinia)
store.$state.count = initialState.count
// 序列化狀態(tài)
const stateToTransfer = JSON.stringify(store.$state)
在客戶端,接收服務(wù)器端發(fā)送的狀態(tài),然后恢復(fù)到對(duì)應(yīng)的 Store 中。
// client.js
import { createPinia } from 'pinia'
import { createApp } from 'vue'
import App from './App.vue' // Vue 應(yīng)用的根組件
import useMyStore from '@/stores/myStore'
const pinia = createPinia()
// 假設(shè)從服務(wù)器接收的狀態(tài)如下
const stateFromServer = JSON.parse(/* state serialized from server */)
// 創(chuàng)建 Store 實(shí)例并恢復(fù)狀態(tài)
const store = useMyStore(pinia)
store.$state.count = stateFromServer.count
const app = createApp(App)
app.use(pinia)
app.mount('#app')
在 Vue 組件中,像平常一樣使用 Store。
<template>
<div>{{ count }}</div>
</template>
<script setup>
import { computed } from 'vue'
import useMyStore from '@/stores/myStore'
const store = useMyStore()
const count = computed(() => store.count)
</script>
defineStore
定義一個(gè) Pinia Store。JSON.stringify
序列化狀態(tài)。$state
中。一句話,Pinia支持SSR有助于提高應(yīng)用的初始加載性能和SEO優(yōu)化。
在 Pinia 中,映射輔助函數(shù)用于將 Store 中的狀態(tài)(state)、獲取器(getters)、動(dòng)作(actions)映射到組件的計(jì)算屬性(computed properties)、方法(methods)或響應(yīng)式屬性上。這些輔助函數(shù)提供了一種便捷的方式來使用 Store,而無需在每個(gè)組件中重復(fù)編寫相同的代碼。
Pinia 的映射輔助函數(shù)主要包括:
mapState
:將 Store 中的狀態(tài)映射為組件的計(jì)算屬性。mapGetters
:將 Store 中的獲取器映射為組件的計(jì)算屬性。mapActions
:將 Store 中的動(dòng)作映射為組件的方法。下面是一個(gè)使用 Pinia 映射輔助函數(shù)的步驟解析,包括代碼示例:
首先,定義一個(gè) Pinia Store。
import { defineStore } from 'pinia'
export const useCartStore = defineStore('cart', {
state: () => ({
items: []
}),
getters: {
itemCount: (state) => state.items.length
},
actions: {
addItem(item) {
this.items.push(item)
}
}
})
在組件中,使用 mapState
、mapGetters
和 mapActions
將 Store 的屬性映射到組件上。
<template>
<div>
<p>Item Count: {{ itemCount }}</p>
<button @click="addItem({ id: 1, name: 'Apple' })">Add Apple</button>
</div>
</template>
<script setup>
import { mapState, mapGetters, mapActions } from 'pinia'
import useCartStore from '@/stores/cart'
const store = useCartStore()
// 使用 mapState 映射狀態(tài)
const items = mapState(store, 'items')
// 使用 mapGetters 映射獲取器
const itemCount = mapGetters(store, 'itemCount')
// 使用 mapActions 映射動(dòng)作
const { addItem } = mapActions(store, ['addItem'])
</script>
在組件的模板中,直接使用映射的計(jì)算屬性和方法。
<p>Item Count: {{ itemCount }}</p>
<button @click="addItem({ id: 1, name: 'Apple' })">Add Apple</button>
defineStore
定義一個(gè)包含狀態(tài)、獲取器和動(dòng)作的 Pinia Store。mapState
:將 items
狀態(tài)映射為組件的計(jì)算屬性。mapGetters
:將 itemCount
獲取器映射為組件的計(jì)算屬性。mapActions
:將 addItem
動(dòng)作映射為組件的方法。itemCount
來顯示項(xiàng)目數(shù)量,使用映射的方法 addItem
來添加新項(xiàng)目。使用映射輔助函數(shù),Pinia 可以讓開發(fā)者以聲明式的方式在組件中使用 Store 的狀態(tài)和行為,從而減少樣板代碼并提高組件的可讀性和可維護(hù)性。此外,這些輔助函數(shù)還有助于保持響應(yīng)性,確保當(dāng) Store 中的狀態(tài)變化時(shí),組件能夠自動(dòng)更新。
不得不說,Pinia 提供了一種靈活且高效的方式來管理 Vue 應(yīng)用的狀態(tài),無論是在單頁應(yīng)用還是服務(wù)器端渲染的場(chǎng)景下,都有出色的表現(xiàn),寫完收工,歡迎關(guān)注威哥愛編程,一起走全棧之路。
更多建議: