介绍
Pinia最初是在 2019 年 11 月左右重新设计使用Composition API 的Vue Store 外观的实验。从那时起,最初的原则仍然相同,但 Pinia 适用于 Vue 2 和 Vue 3 ,并且不需要你使用组合 API。今天来聊聊初次使用pinia的体验和使用过程。
使用
vuex 安装
使用vuex直接在终端中通过npm 或者 yarn安装即可
npm install vuex@next --save
# or with yarn
yarn add vuex@next --save
vuex使用
首先定义全局的 store。
你可以使用包含创建基本store所需的state、mutations、actions和 getters 的对象,并且调用 createStore
方法生成store:
import {createStore} from 'vuex'
const useStore = createStore({
state: {
todos: [ { id: 1, title: '...', done: true } ]
},
mutations:{
},
actions:{
},
getters: {
doneTodos (state) {
return state.todos.filter(todo => todo.done)
}
}
})
然后在项目入口main.js中引入store实例使用即可,
//main.js
import { createApp } from 'vue'
import App from './App.vue'
import {useStore} from './store'
createApp(App).use(store).mount('#app')
本文只对比vuex和pinia,具体vuex教程,移步此处
pinia 安装
其实pinia的使用很简单,可以说和vuex几乎一样,也是直接在终端中通过yarn或者npm直接安装即可。
yarn add pinia@next
# or with npm
npm install pinia@next
pinia 使用
首先也是需要创建生成store,但pinia并不是创建的组件实例,而是通过参数生成的一个函数。 还有就是state并不是作为一个对象直接配置key,value的形式,而是使用一个工厂函数,来对state进行return,其目的是为了在服务端渲染的时候,避免交叉请求导致数据状态污染,并且在pinia中取消了mutations对象,所有的修改都是通过提交actions来进行实现的。因为在pinia中,action都被定义成为了普通函数,只需要在使用store的地方直接通过函数调用传递参数就可以。
import { defineStore } from 'pinia'
export const userStore = defineStore('user', {
state: () => {
return {
name: "秦厅",
age: 18
}
},
actions: {
SET_USER(obj) {
this.name = obj.name
this.age = obj.age;
}
},
getters:{
}
})
定义完实例依然是在项目的入口文件main.js中引入
import { createPinia } from 'pinia'
app.use(createPinia())
项目中的使用
vuex在项目中
vuex3的时候需要借助辅助函数 mapMutations 和 mapActions 来对 store 内的状态进行修改。
如果访问全局store,通过 this.$store 也可以访问。
import { mapGetters,mapMutations } from "vuex";
methods: {
...mapMutations(['SET_SINGLE'])
}
computed: {
error() {
return this.$store.getters.error;
},
...mapGetters(["navBar"])
},
vuex4的时候只需要在组件中直接通过 useStore 创建 store 实例 ,然后通过 store 即可访问各个模块的状态值。
import { useStore } from "vuex";
<script lang="ts" setup>
import { useStore } from "vuex";
<template>
<div class="content">
<a-spin :spinning="store.getters.isLoading" :tip="'加载中...'">
<router-view v-if="isRouterAlive"></router-view>
</a-spin>
</div>
</template>
import { provide, ref, nextTick } from "vue";
let store = useStore();
const reload = () => {
isRouterAlive.value = false;
nextTick(() => {
isRouterAlive.value = true;
});
};
provide("reload", reload);
</script>
具体vuex4
教程,请点击
pinia在项目中
其实大致相仿,不过 pinia 定义的不是组件实例,而是一个方法,我们需要在组件中去调用这个方法来生成组件实例,这也是 pinia 的优点之一,它只会在你调用的时候才会生成实例
import { userStore } from '../store/user';
setup() {
let store = userStore();
console.log(store.name)
}
但是当我们打印的时候,会发现 pinia 对状态值都做了 reactive 响应式的处理,所以我们使用的时候需要将值给解构出来。修改的话只需要通过 store.$patch 来进行修改,如果是异步的话,可以直接通过调用在 actions 里定义的方法来进行批量修改。
import { storeToRefs } from 'pinia';
import { userStore } from '../store/user';
import { onMounted } from 'vue';
setup(){
let store = userStore(),
{ name, age } = storeToRefs(store);
const updateUser = () => {
store.$patch(state => {
state.name = '刘厅';
state.age = '19';
});
};
onMounted(() => {
setTimeout(() => {
let obj = {
name: '郭小白',
age: 24
};
store.SET_USER(obj);
}, 5000);
});
return {
name,
age,
updateUser
};
}
作为第一次使用 pinia 来说,这个感觉来说比 vuex 要好用一点,但是如果是大型项目的话,可能优先级还是 vuex 更高一点,但是 pinia 体积更小啊!
总结Pinia
- 无需创建自定义复杂包装器来支持 TypeScript,所有内容都是类型化的,并且 API 的设计方式尽可能利用 TS 类型推断。
- 不再需要注入借助辅助函数、直接调用它们的方法,享受自动完成功能!
- 无需动态添加商店,默认情况下它们都是动态的,只有在调用的时候才会生成实例。
- 不再有类似 vuex 中模块的嵌套结构。
后续使用发现其他的,会持续更新…