Pinia 快速上手运用
相比于Vuex 4.X而言Pinia可以很好的区分相应的Hooks不必要像Vuex 一样先调用useStore获取我们的Store。
单独的Hooks可以很好的区分我们的模块和业务,不必像Vuex中module那样调用复杂。
同时去掉了Vuex Mutations属性,正常开发中其实这个属性非常鸡肋。
两者相比,明显Pinia更适合Vue3的setup,同时更好兼容TypeScript。
前言:
在使用Pinia前需要使用对应的vue app 安装。
import { createPinia } from 'pinia'// vue app创建流程
app.use(createPinia()); // 安装pinia
一、声明一个Store
1 import {defineStore} from 'pinia'; 2 3 export const useUserInfo = defineStore('userInfo', { 4 state: () => ({ 5 name: 'lisi', 6 age: 18, 7 }), 8 getters: { 9 userName: (state) => state.name, 10 getAuthCode(state) { // 此使用方式将失去本身缓存能力 单纯作函数使用 11 return (id) => [Code]; 12 } 13 }, 14 actions: { 15 setName(newName) { 16 this.name = newName; 17 } 18 } 19 });
可以看到在我们声明的actions中可以直接调用this.xxx 即可调用到我们的state中声明的属性,相比vuex 4.x 需要调用 commit 还是比较友好的。
建议还是使用actions
同时我们想要清除掉当前的Store可以接收其返回值并调用$reset函数。
<script setup lang="ts"> import { useUserInfo } from './store'; const userInfoStore = useUserInfo(); // 重置状态 userInfoStore.$reset(); // 改变状态 userInfoStore.$patch({name: "张三"}); // 可以传入部分的state属性,会根据传入属性更新state,但是此种修改比较低能。 userInfoStore.$patch((state) => { state.name = 'wangwu'; }); // 方便修改和精确调整其接受函数回调提供修改state,因为其属性为响应式的所以可以直接修改。
// 替换整个state userInfoStore.$state = {sex: 1}; // 此方式就可以替换掉当前的store的state </script>
二、调用其他的Store
其实调用其他的store非常简单,可能你已经想到了!没错,就是导入我们声明的useUserInfo;
import {defineStore} from 'pinia'; import { useUserInfo } './store'; export const useUserAuthCode = defineStore('userAuthCodes', { state: () => { userCodes: [], }, actions: { getUserAuthCodeById(state) { const userStore = useUserInfo(); // 获取useInfoStore,getters中也是如此使用 // todo 异步请求 this.userCodes = []; // 获取到的数据 } } });
三、订阅监听
(1)State的监听 store.$subscribe(callback, options);
<script steup> import { useUserInfo } from './store'; const userInfoStore = useUserInfo(); userInfoStore.$subscribe((mutation, state) => { // import { MutationType } from 'pinia' mutation.type // 'direct' | 'patch object' | 'patch function' // 与 userInfoStore.$id 相同 mutation.storeId // 'cart' // 仅适用于 mutation.type === 'patch object' mutation.payload // 补丁对象传递给 to userInfoStore.$patch() // 做自己需要监听的事情 }); </script>
监听事件默认绑定到当前组件实例上,组件卸载会自动移除,想要保留其状态需要设置它的options = { detatched: true }。
其特点与watch非常类似,但是$subscribe只在 patches 之后触发一次。
(2) 监听actions store.$onActions(callback, boolean);
import { useUserInfo } form './store'; const userInfoStore = useUserInfo(); const unUserInfoSubscribe = userInfoStore.$onAction(({ name, // action 的名字, store, // store 实例 args, // 调用这个 action 的参数 after, // 在这个 action 执行完毕之后,执行这个函数 onError, // 在这个 action 抛出异常的时候,执行这个函数 }) => { // 如果 action 成功并且完全运行后,after 将触发。 // 它将等待任何返回的 promise // 如果 action 抛出或返回 Promise.reject ,onError 将触发 }, true); // 第二位参数标识当前组件卸载后保留状态 unUserInfoSubscribe(); // 卸载监听
监听事件默认绑定到当前组件实例上,组件卸载会自动移除。
四、非setup的使用
import { mapState, mapActions } from 'pinia' import { useUserInfo } from '../store' export default { computed: { // state | getters // 允许访问组件内的 this.userName // 与从 store.userName中读取相同 ...mapState(useUserInfo , ['userName']) // 与上面相同,但将其注册为 this.name ...mapState(useUserInfo , { name: 'userName', // 您还可以编写一个访问 store 的函数 userAge: store => store.userName, }) }, methods: { ...mapActions(useUserInfo, ['setName']), ...mapActions(useUserInfo, { setUserName: 'setName', }), }, };
两个mapXXX都需要两个参数,第一个是我们定义的Store函数,第二个参数可以是数组和对象,数组中声明对应的state或actions中存在key名称,对象则可以声明自定义的key:对应声明的Key。
mapState中对象类型options还可以声明函数,接收一个store可以任意访问state中的参数。大致与vuex 3.x版本差不多。
tips: Pinia肯定也是拥有组合式的写法,语法和我们自定义Hooks是一样的,还有嵌套的Store,它的书写方式参考Getters,Actions的共享状态。