vue状态管理库pinia(家人们!赶紧学起来)

对于学习Vue的小伙伴来说,我们会遇到这样一个问题,当我们的组件足够多的时候,我们可能就会有这样一个需求,A组件的值怎么在B组件中去使用呢?(两个组件可能既不是兄弟组件也不是父子组件)

在我们寻找答案的过程中,我们可能听到状态管理一词。进而引出我们今天的主题Pinia

ps:vue对于组件传值的方法有很多,后面有时间我会仔细跟大家唠叨唠叨,本文只是为了引出主题,举例可能不太恰当,望谅解!!!嘿嘿。

一、为什么学习Pinia

对于博主自己提出的问题,我认为作为开发人员,首先要有一颗谦卑的心,其次是不断的学习和探索,我们都喜欢和优秀的人共事,学习亦是如此。

1. Pinia是什么

根据Pinia官网给出的解释,PiniaVue的专属状态管理库,注意这个专属很有牌面,它允许跨组件或页面共享状态。沒骗大家吧,跨组件用它准好使。

2. 什么是Store

我理解的Store更像是一个大仓库,它里面装着各种各样的杂物,对应到我们的Store就是三个状态stategetteraction

3. Pinia优势

这里我提一嘴Vuex,其实Vuex同样是一个优秀的Vue状态管理库。而且Pinia是Vuex的迭代产品。那么为什么标题写的是Pinia而不是Vuex呢?只能说作者在工作中更倾向于使用Pinia。趁着热乎劲,也就跟大家分享分享,仅此而已。

其实两者比较,给我最直观的感受有那么几点:

  1. 开发由选项式组合式API风格迈进

    我在使用Vuex的时候大多以选项式为主,不符合我写Vue3的习惯(组合式API),但是在Pinia中我可以快乐的使用组合式API

  2. 极致的轻量化

    Pinia 大小只有 1kb 左右,体积可是相当的小,基本可以无视它的存在!

  3. 代码编写更加合理(简化)

    如果使用的是Vuex,我们要考虑异步的问题,如果我们的操作存在异步,我们就需要在action中进行,然后在mutation中变更状态(正常操作下),然而PiniaAPI更加简单,它的action支持同步异步。有着Vue3的组合式API风格,与Typescript有着很好的配合,并且同时适配Vue2和Vue3。

  4. 更好的模块管理

    有别于Vuexmodule,Pinia让我们更方便的定义Store,每一个Store都是独立的,并且互不影响。

    值得注意的是Vite官网脚手架已经推荐使用Pinia啦。

二、Pinia技能展示

本小节列举的案例都采用的是选项式API,组合式API我不好给大家展示getters,如果大家看我写的很水的话也可以移步到Pinia官网查看学习,如果大家要喷我,可不可以轻一点。另外再吐槽两句,这个Pinia名字起的是真好。

1. 安装Pinia

  1. 使用Pinia的第一步就是先要安装它,这个我是在Vue3中进行使用的,找到我们的项目根目录,打开命令行工具,输入一下内容即可↓

    // 如果npm慢大家可以使用cnpm
    npm install pinia // 我这里下载的pinia版本是^2.0.36
    
  2. 找到项目的main.[js/ts],引入我们的Pinia就可以愉快的玩耍喽!!!

     import { 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");
    
  3. 创建我们自己的store
    刚才说的模块化就体现出来了,我们在src目录下新建一个store文件夹,里边是我们每一个模块,创建store需要用到defineStore方法,定义好就可以在我们的Vue中使用啦,接下来看勇宝代码演示↓

    // 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中初始化了↓

export const useUserStore = defineStore('users', {
    state: () => ({
        username: 'iyong',
        phone: '18888888888',
        email: 'iyongbao@outlook.com',
        age: 25
    })
})

就是这么简单几句话,我们就可以在组件中进行使用了。

2. 使用state

我们来到首页,假如我们已经登录成功了,跳转到欢迎页面(src/views/home/index.vue)

<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的数据

import { useUserStore } from '@/store/user.ts'
const userStore = useUsersStore();
const { username } = userStore

3. 修改state

这里需要注意了,通过上面的方式解构出来的变量会丢掉响应式。修改username的话,发现试图是不会变化的,大家可以自行敲一敲,体验一下,验证一下勇宝说的对不对。

不过呢,大家不用担心,pinia已经给我们考虑到了。我们直接使用它的storeToRefs。

import { storeToRefs } from 'pinia'
import { useUserStore } from '@/store/user.ts' 
const userStore = useUsersStore(); 
// 注意这
const { username } = storeToRefs(userStore)

4. 重置state

如果我们想把state数据还原要怎么操作呢?就比如我们修改用户信息的时候,写了一半觉得不好,突然想重置到之前的数据,重新修改怎么做呢?这里我们就要使用到$state这个方法

<template>
    <button @click="reset">重置信息</button>
</template>
<script setup>
......
const reset = () => {
    userStore.$reset()
}
</script>

5. 批量修改state

如果我们想同时修改用户名、手机号和邮箱,可以像下面这样,但是可能这种场景用得比较少。因为是赋值,所以大家懂的都懂了吧(我们需要把state里边的属性都赋值一个遍)

userStore.$state = {
    username: 'zhangsan',
    phone: '111111111',
    email: 'xxxx@outlook.com',
    age: 25
}

这里我们需要用到$patch方法

userStore.$patch({
    username: 'zhangsan',
    phone: '111111111',
    email: 'xxxx@outlook.com'
})

这个再提一嘴,$patch还有一种写法,接收一个回调函数,可以拿到state

userStore.$patch((state) => {
    state.username = 'zhangsan'
})

3. getter(vue版的计算属性)

1. 编写getter

pinia中的getter属性和vue中的computed基本一样,都需要有一个return返回值。还是使用刚才的例子

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后,我们就可以在组件中进行使用了。

<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就好了。

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传递参数

这个给大家整活一下高级玩法,其实大家在工作中也都用到过,这个概念呢叫做函数科利华,打不出来呢?(柯里化)

// 比如我们写这个一个getter,用户喜欢吃什么
getters: {
    loveFood: function (state) {
        return (food) => {
            return `${ state.username }喜歡吃${ food }`
        } 
    }
}

loveFood的使用

{{ loveFood('披薩')}}

......
const { loveFood } = storeToRefs(userStore)

4. action(业务逻辑层)

前面我们提到的state也好,还是getter也罢,终归它们都是属性(数据),就像我们Vue中的datacomputed一个意思。如果我们想处理一下业务逻辑,比如我们要发送一个http请求,或者是通过一些复杂的逻辑判断来修改某些数据就会感觉getter不妥啦!
这时候action就派上用场了。

注意:actions和Vue中的methods十分的相似,我们可以在actions中编写同步方法和异步方法。

1. 编写一个action

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”>保存邮箱

// store引入
import { useUserStore } from '@/store/user.ts' 
// store创建
const userStore = useUsersStore();
// 调用
const saveEmail = () => {
    userStore.updateEmail('zhangsan@qq.com')
}

当我们点击按钮后,调用store方法,完成邮箱的修改。

三、总结

这是我工作中使用到的一些技术点,可能不是那么的全面,如果大家之前有Vuex的基础的话上手pinia还是很简单的。所以还是希望大家在接触一个新的技术的时候呢?不要产生很大的畏惧感。回顾本文,其实这个pinia也就是那么三块:

stategettersactions

这个给大家埋个坑,大家可以在编写代码的过程中发现,当我们手动刷新网页的时候,我们的store重置了。这是因为我们的Vue组件重新初始化了。那么如何在刷新网页后还能保留我们修改后的store呢?这就要提到数据持久化一词了。这里边涉及到Pinia的插件,以及如何编写一个插件。如果大家感兴趣的话,可以去pinia官网在研究一下这方面的技术。

原文链接:https://juejin.cn/post/7321569896454750219 作者:爱勇宝

(0)
上一篇 2024年1月10日 下午4:59
下一篇 2024年1月10日 下午5:09

相关推荐

发表回复

登录后才能评论