历史搜索

vue状态管理库pinia

游客2024-09-06 07:53:01
目录文章目录
  1. 一、为什么学习 Pinia
  2. 二、Pinia 技能展示
  3. 三、总结

一、为什么学习 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: 'mybj123',
        phone: '18888888888',
        email: 'mybj123@gmail.com',
        age: 28
    })
})

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

2. 使用 state

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

<template>
    <div >尊贵的{{ store.username }},下午好</div>
    // 这样也是可以的
    <div >尊贵的{{ 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: 'mybj123',
        phone: '18888888888',
        email: 'mybj123@gmail.com',
        age: 28
    }),
    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: 'mybj123',
        phone: '18888888888',
        email: 'mybj123@gmail.com',
        age: 28
    }),
    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: 'mybj123',
        phone: '18888888888',
        email: 'mybj123@mybj123.com',
        age: 28
    }),
    getters: {
        // 过了一年涨一岁
        addAge: (state) => state.age + 1;
    },
    actions: {
        updateEmail(payload): {
            this.email = payload
            // 伪代码:我就不给大家写了
            // 发送 http 请求,修改我们的邮箱为新值
        }
    }
})

这里我编写了一个修改用户邮箱的 action,payload(名字随意起,自己能看懂就行)是我们传递的参数。这里我只是简单给大家演示,我们完全可以在这里面写http 异步请求,还有一点大家我们看到,我们 action 定义的方法中的this是指向的当前store

2. 使用 action

<button @click="saveEmail">保存邮箱</button>
// store 引入
import { useUserStore } from '@/store/user.ts' 
// store 创建
const userStore = useUsersStore();
// 调用
const saveEmail = () => {
    userStore.updateEmail('zhangsan@qq.com')
}

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

三、总结

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

stategettersactions

标签:pinia