安装 官网
1 2 3 yarn add pinia npm install pinia
初始化 Pinia 1 2 3 4 5 6 7 import { createPinia } from 'pinia' const pinia = createPinia()pinia.use (SomePiniaPlugin) const app = createApp(App )app .use (pinia)
这里需要注意时间顺序:只有在调用 app.use(pinia) 之后才能调用 useXxxStore()
使用 Store 注意
defineStore 接受一个 id,不同数据源的 id 必须是不同的
不能将 useCounter() 的返回值解构,这会导致数据响应式的丢失
写法一: 更像原先的 vuex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 // 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 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 to Refs() but specifically designed for Pinia stores so methods and non reactive properties are completely ignored.) return { counterStore, j, k, } }, }
Store Getters getters 其实就是 store 的计算属性集合,而且 getter 不能是异步函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 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 (user Id) => state .users.find((user ) => user .id === user Id) }, otherGetter(state ) { // 你还可以调用其他的 store const otherStore = useOtherStore() return state .localData + otherStore.data }, }, }) // store.doubleCount 和 store.doublePlusOne 就可以直接当做属性使用了 // store.getUserById(user Id) 可以当做函数使用
Store Actions action 其实就是 store 的 methods,而且可以是异步函数
1 2 3 4 5 6 7 8 9 10 11 export const useUserStore = defineStore ('users' , { state : () => ({ userData : null , }), actions : { async getUser (token ) { this .userData = await api.post ({ token }) }, }, })
写法二: 推荐这种,符合Vue3 setup的编程模式,让结构更加扁平化
1 2 3 4 5 6 7 8 9 10 11 12 13 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) 批量更新
1 2 3 4 5 6 7 8 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 的整体变化。
1 2 3 4 5 6 7 8 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 达到类似的效果:
1 2 3 4 5 6 7 watch( pinia.state , (state ) => { localStorage.set Item('piniaState', JSON.stringify(state )) }, { deep: true } )
store.$onAction() 用于监控所有 action 的执行情况。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const unsubscribe = someStore.$o nAction( ({ name, store, args, after, 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} .` ) }) } )
store.$reset() 你可以使用 counterStore.$reset() 重置 state
store.$state 1 2 3 // 下面两句代码都能覆盖原有 state store.$state = { counter: 666 , name: 'Paimon' } pinia.state .value = {} // 这句常用在 SSR