安装
官网
yarn add pinia# or with npmnpm install pinia初始化 Pinia
import { createPinia } from 'pinia'const pinia = createPinia()pinia.use(SomePiniaPlugin) // 给 pinia 装插件const app = createApp(App)app.use(pinia)这里必要注意时间序次:只有在调用 app.use(pinia) 之后才华调用 useXxxStore()
利用 Store
注意
- defineStore 继承一个 id,差别数据源的 id 必须是差别的
- 不能将 useCounter() 的返回值解构,这会导致数据相应式的丢失
写法一:
更像原先的 vuex
// src/stores/counter.jsimport { defineStore } from 'pinia'export const useCounterStore = defineStore('counterStore', { state: ()=> { return {j: 0, k: 0} }})// Counter.vueimport { 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 // 但你不能解构 counterStore,只能像下面如许解构: const { j, k } = storeToRefs(counterStore) // 注意:这里会自动忽略 方法 和 非相应式数据(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 不能是异步函数
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 可以返回一个函数,不外这会导致缓存失效 return (userId) => state.users.find((user) => user.id === userId) }, otherGetter(state) { // 你还可以调用其他的 store const otherStore = useOtherStore() return state.localData + otherStore.data }, },})// store.doubleCount 和 store.doublePlusOne 就可以直接当做属性利用了// store.getUserById(userId) 可以当做函数利用Store Actions
action 着实就是 store 的 methods,而且可以是异步函数
export const useUserStore = defineStore('users', { state: () => ({ userData: null, }), actions: { async getUser(token) { this.userData = await api.post({ token }) }, },})// 然后你就可以利用 userStore.getUser(token) 了写法二:
保举这种,符合Vue3 setup的编程模式,让布局更加扁平化
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)
用于监听 state 的团体厘革。
cartStore.$subscribe((mutation, state) => { // import { MutationType } from 'pinia' mutation.type // 'direct' | 'patch object' | 'patch function' mutation.storeId mutation.payload // 获取 $patch 吸收到的参数 localStorage.setItem('cart', JSON.stringify(state))})它有一个很方便的特性是会自动在组件卸载时注销,如果你不想要,可以在 $subscribe 第二个参数处传入 {detached: true} 选项。
你也可以利用 watch 到达类似的效果:
watch( pinia.state, (state) => { localStorage.setItem('piniaState', JSON.stringify(state)) }, { deep: true })store.$onAction()
用于监控全部 action 的实行情况。
const unsubscribe = someStore.$onAction( ({ name, // action 的名字 store, // store === someStore args, // action 的现实参数 after, // action 成功之后实行 after onError, // action 失败之后实行 onError }) => { const startTime = Date.now() console.log(`开始实行 "${name}" 参数为 [${args.join(', ')}].`) after((result) => { console.log( `实行成功 "${name}" 用时 ${Date.now() - startTime}毫秒\n效果为:${result}` ) }) onError((error) => { console.warn( `实行失败 "${name}" 用时 ${Date.now() - startTime}毫秒\n报错为:${error}.` ) }) })// $onAction 会在它地点组件卸载时自动烧毁// 如果你将 $onAction 的第二个参数设置为 true,那么你必要本身调用 unsubscribe 来取消监听。store.$reset()
你可以利用 counterStore.$reset() 重置 state
store.$state
// 下面两句代码都能覆盖原有 statestore.$state = { counter: 666, name: 'Paimon' }pinia.state.value = {} // 这句常用在 SSR |