Pinia:Vue状态管理的新纪元

前言

什么是pinia?

pinia是一个用于Vue.js应用的状态管理库,主要作用是在Vue应用的不同组件间共享和管理状态。相当于一个大型的仓库,组件想要什么都能去仓库取。

如果我想实现两个组件的内容都在App.vue上展示,实现兄弟通讯的效果。

  • 首先我们创建一个vue项目
  • 创建以下文件

App.vue

add.vue和count.vue的父组件

vue 复制代码
<template>
    <Add />
    <Count />
</template>

<script setup>
import Add from './components/add.vue'
import Count from './components/count.vue'
</script>

<style lang="css" scoped>

</style>

add.vue

定义一个add按钮,当点击按钮时,num会进行累加。

vue 复制代码
<template>
    <button @click="num++">add</button>
</template>

<script setup>
import {num} from '@/global.js'
</script>

<style lang="css" scoped>

</style>

count.vue

将num从global.js引入进来

vue 复制代码
<template>
    <div>
        <h2>{{ num }}</h2>
    </div>
</template>

<script setup>
import {num} from '@/global.js'

</script>

<style lang="css" scoped>

</style>

global.js

定义一个全局变量num并将其抛出,其为响应式变量,当点击add按钮时,num的值会发生变化并且在页面上实时更新。

js 复制代码
import {ref} from 'vue'

export const num = ref(0)

pinia

  • 首先在项目中安装pinia,指令:npm i pinia
  • 安装成功后,在src文件夹下创建一个文件夹store,再到store文件夹下创建一个index.js文件。
  • 在index.js文件下引入createPinia函数,用于创建一个pinia实例,再调用createPinia函数来创建一个新的pinia实例,这个实例就是状态管理仓库,再使用export default将该仓库抛出。
  • 导入pinia-plugin-persist插件添加到store实例中,状态数据会被保存在浏览器的localStorage中。
js 复制代码
import {createPinia} from 'pinia';
import piniaPluginPersist from 'pinia-plugin-persist';

const store = createPinia();
store.use(piniaPluginPersist);

export default store;
  • 要让该仓库在全局生效,就将该仓库引入到main.js当中。
js 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'

createApp(App).use(store).mount('#app')
  • 在store文件夹下创建一个user.js,从pinia模块导入defineStore函数,其作用是创建Pinia store实例,接受一个配置对象作为参数,这个对象包含了store的名字、state、getters、actions、persist等属性。
  • 定义store的id为user,state为仓库的数据源,返回一个userInfo对象,里面包含用户的基本信息,如name、sex、money。
  • actions是方法集合,用于改变store的状态,里面定义了changeUserNamechangeUserSexchangeUserMoney三个方法用于修改用户的信息。
  • getters是仓库中的计算属性,afterMoney返回用户资金加上额外的10000元的结果。
  • persist用于开启数据持久化,即当页面关闭或浏览器重启时,store中的某些状态会被保存到本地存储(localStorage),再次刷新页面数据不会回到初始状态,paths指定哪些状态需要持久化。
  • 要实现持久化存储还需要装一个插件,在终端输入该指令:npm i pinia-plugin-persist
js 复制代码
import { defineStore } from 'pinia';   // defineStore 是store 的一部分

export const useUserStore = defineStore({
    id: 'user',
    state: () => { // 仓库里的数据源
        return{
            userInfo: {
                name: 'lt',
                sex: '男',
                age: 18
            }
        }
    },
    actions: { // 专门用来修改state
        changeUserName(name) {
            this.userInfo.name = name; // 仓库的数据源应该由仓库自己修改
        },
        changeUserSex(sex) {
            this.userInfo.sex = sex;
        },
        changeUserAge(n) {
            this.userInfo.age += n;
        }
    },
    getters: { // 仓库中的计算属性
        afterAge(state) {
            return state.userInfo.age + 10
        }
    },
    persist: { // 开启数据持久化
        enabled: true,
        strategies: [
            {
                paths: ['userInfo'],
                storage: localStorage,
            }
        ]
    }
});

User.vue

在components文件夹下创建一个User.vue文件,并且在App.vue中将该组件引入,用于展示用户的数据。

  • const userStore = useUserStore()将useUserStore的执行结果赋给userStore,即将仓库内的数据赋给了userStore。
  • 由于仓库是响应式的,所以userStore.userInfo.name是响应式数据,所以当仓库内用户的name改变时,页面上的姓名会更新。如果此处换一种写法:
vue 复制代码
<template>
 <li>姓名:{{ name }}</li>
 </template>
 
 <script setup>
 const name = userStore.userInfo.name
 </script>

这种写法在改变了仓库的name之后,页面上的姓名不会更新,因为name不会被重新赋值。虽然userStore.userInfo.name是响应式的,但是name不是响应式的数据。

  • 还可使用computed计算属性将age变成响应式数据,所以当age的值发生变更时,页面会更新age的值。
  • 引入storeToRefs函数,将store中的状态转换为ref对象,由于storeToRefs(userStore)会返回一个对象,于是需要用到解构语法,获得一个名为userInfo的ref对象,就可以直接使用userInfo.sex来访问或者更新store中的userInfo状态。
  • userStore.afterAge不需要写成userStore.afterAge(),因为getter在背后被自动执行,只需要访问其结果,而不需要显示地调用它。
vue 复制代码
<template>
    <ul>
        <li>姓名:{{ userStore.userInfo.name }}</li>
        <li>性别:{{ userInfo.sex }}</li>
        <li>年龄:{{ age }}</li>
        <li>十年之后年龄:{{ userStore.afterAge }}</li>
    </ul>
</template>

<script setup>
import {computed} from "vue";
import {useUserStore} from "@/store/user";
import {storeToRefs} from "pinia";

const userStore = useUserStore();

const age = computed(() => userStore.userInfo.age)
const {userInfo} = storeToRefs(userStore) // storeToRefs 把整个仓库的数据源变成一个响应式对象

// console.log(userStore);
</script>

<style lang="css" scoped>

</style>

Update-user.vue

在components文件夹下再创建一个Update-user.vue文件,里面放入一些按钮,当点击按钮时改变相应的数据。将该组件也引入App.vue

  • 分别为这些按钮绑定点击事件,在仓库中的actions中写入一些方法,当点击按钮时则会访问userStore内的方法,通过调用这些方法来改变相应变量的值。
vue 复制代码
<template>
    <button @click="changeName">修改仓库中的用户姓名</button>
    <button @click="changeSex">修改仓库中的用户性别</button>
    <button @click="changeAge">年龄</button>
</template>

<script setup>
import {useUserStore} from '@/store/user';
const userStore = useUserStore();

const changeName = () =>{
    // userStore.userInfo.name = 'ltt';  // 不要这种代码
    userStore.changeUserName('ltt');
};
const changeSex = () =>{
    userStore.changeUserSex('女');
};
const changeAge = (n) =>{
    userStore.changeUserAge(1);
};
</script>

<style lang="css" scoped>

</style>

最终执行结果

结语

快自己动手敲一敲吧

相关推荐
mez_Blog1 小时前
个人小结(2.0)
前端·javascript·vue.js·学习·typescript
珊珊而川1 小时前
【浏览器面试真题】sessionStorage和localStorage
前端·javascript·面试
森叶1 小时前
Electron 安装包 asar 解压定位问题实战
前端·javascript·electron
深情废杨杨1 小时前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js
GHUIJS1 小时前
【vue3】vue3.3新特性真香
前端·javascript·vue.js
markzzw1 小时前
我在 Thoughtworks 被裁前后的经历
前端·javascript·面试
众生回避2 小时前
鸿蒙ms参考
前端·javascript·vue.js
笃励2 小时前
Angular面试题五
javascript·ecmascript·angular.js
GHUIJS2 小时前
【vue3】vue3.5
前端·javascript·vue.js
-seventy-2 小时前
对 JavaScript 原型的理解
javascript·原型