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>

最终执行结果

结语

快自己动手敲一敲吧

相关推荐
我命由我123451 小时前
React Router 6 - 编程式路由导航、useInRouterContext、useNavigationType
前端·javascript·react.js·前端框架·html·ecmascript·js
橙露2 小时前
JavaScript 异步编程:Promise、async/await 从原理到实战
开发语言·javascript·ecmascript
我命由我123453 小时前
React Router 6 - 嵌套路由、路由传递参数
前端·javascript·react.js·前端框架·html·ecmascript·js
十六年开源服务商3 小时前
2026年WordPress网站地图完整指南
java·前端·javascript
英俊潇洒美少年4 小时前
MessageChannel 如何实现时间切片
javascript·react.js·ecmascript
技术钱5 小时前
react数据大屏四种适配方案
javascript·react.js·ecmascript
李明卫杭州5 小时前
JavaScript 严格模式下 arguments 的区别
前端·javascript
一次旅行6 小时前
今日心理学知识分享(三)
开发语言·javascript·程序人生·ecmascript
牛十二6 小时前
openclaw安装mcporter搜索小红书
开发语言·javascript·ecmascript
小金鱼Y6 小时前
🔥 前端人必看:浏览器安全核心知识点全解析(XSS/CSRF/DDoS)
前端·javascript·安全