安裝
yarn add pinia
# or with npm
npm install pinia
初始化 Pinia
import { createPinia } from 'pinia'
const pinia = createPinia()
pinia.use(SomePiniaPlugin) // 給 pinia 裝插件
const app = createApp(App)
app.use(pinia)
這里需要注意時間順序:只有在調(diào)用 app.use(pinia) 之后才能調(diào)用 useXxxStore()
使用 Store
注意
- defineStore 接受一個 id姻檀,不同數(shù)據(jù)源的 id 必須是不同的
- 不能將 useCounter() 的返回值解構(gòu)芥炭,這會導致數(shù)據(jù)響應式的丟失
寫法一:
更像原先的 vuex
// src/stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counterStore', {
state: ()=> {
return {j: 0, k: 0}
}
})
// Counter.vue
import { useCounterStore } from 'path/to/src/stores/counterStore'
export default {
setup() {
const counterStore = useCounterStore()
// TODO 默認情況下可以直接這么更改,但是不推薦 // https://pinia.vuejs.org/core-concepts/state.html#accessing-the-state
counterStore.j ++
// 這里在視圖里使用 counterStore.j 和 counterStore.k
// 但你不能解構(gòu) counterStore氛濒,只能像下面這樣解構(gòu):
const { j, k } = storeToRefs(counterStore) // 注意:這里會自動忽略 方法 和 非響應式數(shù)據(jù)(Creates an object of references with all the state, getters, and plugin-added state properties of the store. Similar to toRefs() but specifically designed for Pinia stores so methods and non reactive properties are completely ignored.)
return {
counterStore, j, k,
}
},
}
Store Getters
getters 其實就是 store 的計算屬性集合部服,而且 getter 不能是異步函數(shù)
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount(state) {
return state.counter * 2
},
doublePlusOne() {
return this.doubleCount + 1 // getter 訪問另一個 getter 或者 state 可以用 this
},
getUserById: (state) => { // getter 可以返回一個函數(shù)唆姐,不過這會導致緩存失效
return (userId) => state.users.find((user) => user.id === userId)
},
otherGetter(state) { // 你還可以調(diào)用其他的 store
const otherStore = useOtherStore()
return state.localData + otherStore.data
},
},
})
// store.doubleCount 和 store.doublePlusOne 就可以直接當做屬性使用了
// store.getUserById(userId) 可以當做函數(shù)使用
Store Actions
action 其實就是 store 的 methods,而且可以是異步函數(shù)
export const useUserStore = defineStore('users', {
state: () => ({
userData: null,
}),
actions: {
async getUser(token) {
this.userData = await api.post({ token })
},
},
})
// 然后你就可以使用 userStore.getUser(token) 了
寫法二:
推薦這種廓八,符合Vue3 setup的編程模式奉芦,讓結(jié)構(gòu)更加扁平化
import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
export const useUserStore = defineStore('users', () => {
const userData= ref({});
const getUser = async () => {
userData.value = await api.post({ token })
}
const userName = computed(() => userData.value.name)
return { userData, userName, getUser };
});
store.$patch(object | fn)
批量更新
counterStore.$patch(
{ name: 'pinia', age: counterStore.age + 1 }
)
cartStore.$patch((state) => {
state.items.push({ name: 'vuex', age: 18 })
state.hasChanged = true
})
store.$subscribe(fn)
用于監(jiān)聽 state 的整體變化。
cartStore.$subscribe((mutation, state) => {
// import { MutationType } from 'pinia'
mutation.type // 'direct' | 'patch object' | 'patch function'
mutation.storeId
mutation.payload // 獲取 $patch 接收到的參數(shù)
localStorage.setItem('cart', JSON.stringify(state))
})
它有一個很方便的特性是會自動在組件卸載時注銷剧蹂,如果你不想要声功,可以在 $subscribe 第二個參數(shù)處傳入
{detached: true}
選項。
你也可以使用 watch 達到類似的效果:
watch(
pinia.state,
(state) => {
localStorage.setItem('piniaState', JSON.stringify(state))
},
{ deep: true }
)
store.$onAction()
用于監(jiān)控所有 action 的執(zhí)行情況宠叼。
const unsubscribe = someStore.$onAction(
({
name, // action 的名字
store, // store === someStore
args, // action 的實際參數(shù)
after, // action 成功之后執(zhí)行 after
onError, // action 失敗之后執(zhí)行 onError
}) => {
const startTime = Date.now()
console.log(`開始執(zhí)行 "${name}" 參數(shù)為 [${args.join(', ')}].`)
after((result) => {
console.log(
`執(zhí)行成功 "${name}" 用時 ${Date.now() - startTime}毫秒\n結(jié)果為:${result}`
)
})
onError((error) => {
console.warn(
`執(zhí)行失敗 "${name}" 用時 ${Date.now() - startTime}毫秒\n報錯為:${error}.`
)
})
}
)
// $onAction 會在它所在組件卸載時自動銷毀
// 如果你將 $onAction 的第二個參數(shù)設置為 true先巴,那么你需要自己調(diào)用 unsubscribe 來取消監(jiān)聽。
store.$reset()
你可以使用 counterStore.$reset() 重置 state
store.$state
// 下面兩句代碼都能覆蓋原有 state
store.$state = { counter: 666, name: 'Paimon' }
pinia.state.value = {} // 這句常用在 SSR