对于学习
Vue
的小伙伴来说,我们会遇到这样一个问题,当我们的组件足够多的时候,我们可能就会有这样一个需求,A组件
的值怎么在B组件
中去使用呢?(两个组件可能既不是兄弟组件也不是父子组件)在我们寻找答案的过程中,我们可能听到
状态管理
一词。进而引出我们今天的主题Pinia
。ps:
vue
对于组件传值的方法有很多,后面有时间我会仔细跟大家唠叨唠叨,本文只是为了引出主题,举例可能不太恰当,望谅解!!!嘿嘿。
一、为什么学习Pinia
对于博主自己提出的问题,我认为作为开发人员,首先要有一颗谦卑的心,其次是不断的学习和探索,我们都喜欢和优秀的人共事,学习亦是如此。
1. Pinia是什么
根据Pinia官网给出的解释,Pinia
是Vue
的专属状态管理库
,注意这个专属
很有牌面,它允许你 跨组件或页面共享状态。沒骗大家吧,跨组件
用它准好使。
2. 什么是Store
我理解的Store 更像是一个大仓库,它里面装着各种各样的杂物,对应到我们的Store就是三个状态state
、getter
、action
。
3. Pinia优势
这里我提一嘴Vuex
,其实Vuex同样是一个优秀的Vue状态管理库。而且Pinia是Vuex的迭代产品。那么为什么标题写的是Pinia而不是Vuex呢?只能说作者在工作中更倾向于使用Pinia。趁着热乎劲,也就跟大家分享分享,仅此而已。
其实两者比较,给我最直观的感受有那么几点:
-
开发由
选项式
向组合式API
风格迈进我在使用Vuex的时候大多以选项式为主,不符合我写Vue3的习惯(组合式API),但是在Pinia中我可以快乐的使用
组合式API
。 -
极致的轻量化
Pinia
大小只有1kb
左右,体积可是相当的小,基本可以无视它的存在! -
代码编写更加合理(简化)
如果使用的是
Vuex
,我们要考虑异步
的问题,如果我们的操作存在异步,我们就需要在action 中进行,然后在mutation 中变更状态(正常操作下),然而Pinia
的API
更加简单,它的action支持同步
和异步
。有着Vue3的组合式
API风格,与Typescript
有着很好的配合,并且同时适配Vue2和Vue3。 -
更好的模块管理
有别于
Vuex
的module
,Pinia让我们更方便的定义Store,每一个Store都是独立的
,并且互不影响。值得注意的是Vite官网脚手架已经推荐使用Pinia啦。
二、Pinia技能展示
本小节列举的案例都采用的是
选项式API
,组合式API我不好给大家展示getters
,如果大家看我写的很水的话也可以移步到Pinia官网查看学习,如果大家要喷我,可不可以轻一点。另外再吐槽两句,这个Pinia名字起的是真好。
1. 安装Pinia
-
使用Pinia的第一步就是先要安装它,这个我是在Vue3中进行使用的,找到我们的项目根目录,打开命令行工具,输入一下内容即可↓
js// 如果npm慢大家可以使用cnpm npm install pinia // 我这里下载的pinia版本是^2.0.36
-
找到项目的main.[js/ts],引入我们的Pinia就可以愉快的玩耍喽!!!
jsimport { createApp } from "vue"; import App from "./App.vue"; import { createPinia } from "pinia"; // 加上这一句 const pinia = createPinia(); // 还有这一句 const app = createApp(App); app.use(pinia); // 这一句 app.mount("#app");
-
创建我们自己的store 刚才说的模块化就体现出来了,我们在
src目录
下新建一个store文件夹
,里边是我们每一个模块,创建store需要用到defineStore方法,定义好就可以在我们的Vue中使用啦,接下来看勇宝代码演示↓ts// src/store/user.ts import { defineStore } from 'pinia' // defineStore的第一个参数是一个唯一标识(id),就跟我们每个人的身份证一样一样滴。 export const useUserStore = defineStore('users', { // 一些具体的配置属性,我们后面一一讲解 })
这里是我创建了一个user的store,比如我们自己的网站,当用户登录成功后端返回给我们一些用户的个人信息,我们把它存到这个store里边。
2. state(状态初始化)
1. 初始化state
比如我们的用户信息有username
(用户名),phone
(手机号),email
(邮箱),age
(年龄),那么我们就需要在state中初始化了↓
ts
export const useUserStore = defineStore('users', {
state: () => ({
username: 'iyong',
phone: '18888888888',
email: 'iyongbao@outlook.com',
age: 25
})
})
就是这么简单几句话,我们就可以在组件中进行使用了。
2. 使用state
我们来到首页,假如我们已经登录成功了,跳转到欢迎页面(src/views/home/index.vue)
ts
<template>
<div class="username">尊贵的{{ store.username }},下午好</div>
// 这样也是可以的
<div class="username">尊贵的{{ store.$state.username }},下午好</div>
</template>
<script setup>
import { useUserStore } from '@/store/user.ts'
const userStore = useUsersStore();
</script>
看到了吗?就是这么的简单,我们可以直接对store.username
进行修改,如果觉得繁琐我们也可以进行解构。
另外注意:userStore.$state也能拿到store的数据
ts
import { useUserStore } from '@/store/user.ts'
const userStore = useUsersStore();
const { username } = userStore
3. 修改state
这里需要注意了,通过上面的方式解构出来的变量会丢掉响应式。修改username的话,发现试图是不会变化的,大家可以自行敲一敲,体验一下,验证一下勇宝说的对不对。
不过呢,大家不用担心,pinia已经给我们考虑到了。我们直接使用它的storeToRefs。
ts
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/store/user.ts'
const userStore = useUsersStore();
// 注意这
const { username } = storeToRefs(userStore)
4. 重置state
如果我们想把state数据还原要怎么操作呢?就比如我们修改用户信息的时候,写了一半觉得不好,突然想重置到之前的数据,重新修改怎么做呢?这里我们就要使用到$state这个方法
ts
<template>
<button @click="reset">重置信息</button>
</template>
<script setup>
......
const reset = () => {
userStore.$reset()
}
</script>
5. 批量修改state
如果我们想同时修改用户名、手机号和邮箱,可以像下面这样,但是可能这种场景用得比较少。因为是赋值,所以大家懂的都懂了吧(我们需要把state里边的属性都赋值一个遍)
ts
userStore.$state = {
username: 'zhangsan',
phone: '111111111',
email: 'xxxx@outlook.com',
age: 25
}
这里我们需要用到$patch方法
ts
userStore.$patch({
username: 'zhangsan',
phone: '111111111',
email: 'xxxx@outlook.com'
})
这个再提一嘴,$patch还有一种写法,接收一个回调函数
,可以拿到state
:
ts
userStore.$patch((state) => {
state.username = 'zhangsan'
})
3. getter(vue版的计算属性)
1. 编写getter
pinia中的getter属性和vue中的computed基本一样,都需要有一个return返回值。还是使用刚才的例子
ts
export const useUserStore = defineStore('users', {
state: () => ({
username: 'iyong',
phone: '18888888888',
email: 'iyongbao@outlook.com',
age: 25
}),
getters: {
// 过了一年涨一岁
addAge: (state) => state.age + 1;
}
})
2. 使用getter
当我们在store中定义好getter后,我们就可以在组件中进行使用了。
ts
<template>
<button @click="updateAge">年龄涨一岁</button>
{{ addAge }}
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/store/user.ts'
const userStore = useUsersStore();
const { age, addAge } = storeToRefs(userStore)
const updateAge = () => {
age.value ++
}
</script>
当我们修改了age后我们的addAge也会进行变更。
当然了我们的getter之间是可以相互调用的,我们可以在我们的getter中使用this.age
就好了。
ts
export const useUserStore = defineStore('users', {
state: () => ({
username: 'iyong',
phone: '18888888888',
email: 'iyongbao@outlook.com',
age: 25
}),
getters: {
// 过了一年涨一岁
addAge: (state) => state.age + 1;
},
showInfo: function (state) {
return `${ state.username }的年龄加1是: ${ this.addAge }`
}
})
这个地方值得我们去注意一下,很重要,大家可以明显的看到这里我没有使用箭头函数,这个里边涉及到this上下文的问题,挖可坑,以后来填。
3. getter传递参数
这个给大家整活一下高级玩法,其实大家在工作中也都用到过,这个概念呢叫做函数科利华,打不出来呢?(柯里化)
ts
// 比如我们写这个一个getter,用户喜欢吃什么
getters: {
loveFood: function (state) {
return (food) => {
return `${ state.username }喜歡吃${ food }`
}
}
}
loveFood的使用
ts
{{ loveFood('披薩')}}
......
const { loveFood } = storeToRefs(userStore)
4. action(业务逻辑层)
前面我们提到的state也好,还是getter也罢,终归它们都是属性(数据)
,就像我们Vue中的data
和computed
一个意思。如果我们想处理一下业务逻辑,比如我们要发送一个http请求
,或者是通过一些复杂的逻辑判断来修改某些数据就会感觉getter
不妥啦! 这时候action
就派上用场了。
注意:
actions和Vue中的methods十分的相似,我们可以在actions中编写同步方法和异步方法。
1. 编写一个action
ts
export const useUserStore = defineStore('users', {
state: () => ({
username: 'iyong',
phone: '18888888888',
email: 'iyongbao@outlook.com',
age: 25
}),
getters: {
// 过了一年涨一岁
addAge: (state) => state.age + 1;
},
actions: {
updateEmail(payload): {
this.email = payload
// 伪代码:我就不给大家写了
// 发送http请求,修改我们的邮箱为新值
}
}
})
这里我编写了一个修改用户邮箱的action,payload
(名字随意起,自己能看懂就行)是我们传递的参数
。这里我只是简单给大家演示,我们完全可以在这里面写http异步请求
,还有一点大家我们看到,我们action定义的方法中的this
是指向的当前store
。
2. 使用action
<button @click="saveEmail">保存邮箱
ts
// store引入
import { useUserStore } from '@/store/user.ts'
// store创建
const userStore = useUsersStore();
// 调用
const saveEmail = () => {
userStore.updateEmail('zhangsan@qq.com')
}
当我们点击按钮后,调用store方法,完成邮箱的修改。
三、总结
这是我工作中使用到的一些技术点,可能不是那么的全面,如果大家之前有Vuex
的基础的话上手pinia
还是很简单的。所以还是希望大家在接触一个新的技术的时候呢?不要产生很大的畏惧感。回顾本文,其实这个pinia也就是那么三块:
state
、getters
、actions
这个给大家埋个坑,大家可以在编写代码的过程中发现,当我们手动刷新网页的时候,我们的store
就重置
了。这是因为我们的Vue组件重新初始化了。那么如何在刷新网页
后还能保留我们修改后的store
呢?这就要提到数据持久化
一词了。这里边涉及到Pinia的插件,以及如何编写一个插件。如果大家感兴趣的话,可以去pinia官网在研究一下这方面的技术。