Vue3状态管理库Pinia简单入门

641 阅读6分钟

前言

pinia是什么?

Pinia 是一个为 Vue.js 应用程序设计的状态管理库。它旨在简化和统一跨组件或页面共享状态的方式,提供了一个直观且强大的 API 来管理应用的全局状态。Pinia 的设计目标是让状态管理变得简单、可预测并且易于调试。

image.png

这个是官方文档:pinia.web3doc.top/大家可以到官方文档里具体查看。

正文

- Pinia的数据流转图

image.png

使用pinia的优点

  • 去除了mutations,只有 state,getters和actions,其中actions支持了同步和异步操作

  • 不会像Vuex那样有模块嵌套,Pinia只有store的概念,store之间可以相互使用,互不影响,达到模块扁平化的效果

  • 更好地支持ts

  • 更好地支持Vue2/Vue3

  • 逻辑更加清晰,开发起来更加简单

  • 可以创建多个全局仓库,不用像 Vuex 一个store嵌套多个modules,结构复杂。

  • 语法简单,不像Vuex需要记忆太多的API。

如何使用pinia

安装

yarn add pinia
# or
npm i pinia

导入,实例化,当做插件使用,和其他插件的使用套路差不多

import { createApp } from 'vue'
+import { createPinia } from 'pinia'
import App from './App.vue'


const app = createApp(App)

+ const pinia = createPinia()
+ app.use(pinia)

app.mount('#app')

创建仓库和使用仓库

在目录src/store/index.js下创建store

import { createPinia } from 'pinia'
const store = createPinia()
export default store

定义一个具体的store

创建目录src/store/user.js

import { defineStore } from 'pinia'  // defineStore 是store的一部分
export const useUserStore = defineStore({
    id: 'user',
    state: () => {   // 数据源
        return {
            userInfo: {
                name: '张三',
                age: 18,
                sex: 'girl'
            }
        }
    }
})

这段代码创建了一个 Store,名为 user,它包含了一个 userInfo 对象作为初始状态。可以在 Vue 组件中通过调用 useUserStore 函数来访问和修改这个 Store 的状态。

获取state

<template>
     <div>{{userStore.userInfo.name}}</div>
</template>

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

同样也可以通过使用computed获取state的值

const name = computed(() => userStore.userInfo.name)

还可以通过storeToRefs将state的值转化为响应式的Refs

const { userInfo } = storeToRefs(userStore)

修改state

在获取到store实例时,咱们可以直接修改state中的变量,但一般不建议这么做,因为这样不利于维护,而是通过在actions中定义一些方法来通过this访问该变量去修改。


import { defineStore } from 'pinia'  // defineStore 是store的一部分

export const useUserStore = defineStore({
    id: 'user',
    state: () => {   // 数据源
        return {
            userInfo: {
                name: '张三',
                age: 18,
                sex: 'girl'
            }
        }
    },
    actions: {  // 专门用来修改state
        changeUserName(name) {
            this.userInfo.name = name
        }
    }
})

通过调用actions中的咱们定义的方法来修改变量的值:


<template>
    <button @click="changeName">修改仓库中的用户姓名</button>
</template>

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

const changeName = () => {
    // userStore.userInfo.name = '李四'  // 不要这种代码
    userStore.changeUserName('李四')
}
</script>
<style lang="css" scoped></style>

getters

在 Pinia 中,getters 被用于定义基于 Store 状态的派生数据。它们是响应式的,这意味着每当 Store 的状态发生变化时,相关的 getters 将会自动更新,所有依赖于这些 getters 的组件也会随之更新。类似于 Vue.js 中的 computed 属性.

import { defineStore } from 'pinia'  // defineStore 是store的一部分

export const useUserStore = defineStore({
    id: 'user',
    state: () => {   // 数据源
        return {
            userInfo: {
                name: '张三',
                age: 18,
                sex: 'girl'
            }
        }
    },
    actions: {  // 专门用来修改state
        changeUserName(name) {
            this.userInfo.name = name
        }
    },
    getters: {  // 仓库中的计算属性
        afterAge(state) {
            return state.userInfo.age + 10
        }
    }
})
<template>
    <ul>
        
        <li>十年后年龄:{{ userStore.afterAge }}</li> //28
    </ul>
</template>

<script setup>
import { useUserStore } from '@/store/user'
const userStore = useUserStore()
</script>
<style lang="scss" scoped></style>

数据持久化

在前端中我们的数据是无法保存的,一但重新刷新了页面,数据就会重新回到初始状态,为了解决这个问题我们可以把数据存储在浏览器的本地存储当中,这就叫数据持久化。

通过安装插件pinia-plugin-persist 可以实现数据持久化功能。

npm i pinia-plugin-persist

如何使用

  1. enabled: true:表明数据持久化功能是启用的。如果没有这行代码或设置为 false,那么持久化将不会生效。

  2. strategies 数组:持久化策略定义了哪些数据路径(paths)需要被持久化以及使用哪种存储机制(storage)。

    • paths: ['userInfo']:这里指定了 userInfo 这个状态路径应该被持久化。这意味着 userInfo 下的所有数据都会被序列化并存储起来。如果你有多个状态路径需要持久化,可以在这里添加更多的路径。

    • storage: localStorage:指定了使用 localStorage 作为持久化存储机制。localStorage 是浏览器提供的一种持久化存储方案,它允许在用户的浏览器中存储数据,即使用户关闭浏览器,数据也不会丢失,除非用户主动清除。

import { defineStore } from 'pinia'  // defineStore 是store的一部分

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

persist 对象配置了数据持久化策略。在这里,咱们启用了数据持久化功能,指定了 userInfo 路径的数据应该被持久化,并且使用 localStorage 作为存储机制。这意味着 userInfo 的数据将在浏览器的 localStorage 中保存,即使用户刷新页面或关闭浏览器,数据也不会丢失。

开启数据持久化

import { createPinia } from 'pinia'
import piniaPluginPersist from 'pinia-plugin-persist'

const store = createPinia()
store.use(piniaPluginPersist)
export default store

完成数据持久化操作之后可以在浏览器中看到,localStorage中的key为该store的id属性user,value为userInfo对象。

一些使用中遇到的问题和注意

  1. 异步操作的处理:Pinia尚未提供类似Vuex中actions的处理异步操作的直接方式。在Pinia中,我们不得不采用async/await操作来处理异步请求。有时,这可能使我们的代码显得更加冗长和复杂。
import { defineStore } from 'pinia'
import axios from 'axios'

export const useUserStore = defineStore({
    id: 'user',
    state: () => ({
        userData: {}
    }),
    actions: {
        async fetchUser() {
            const response = await axios.get('/api/user')
            this.userData = response.data
        }
    }
})

2.为了从 store 中提取属性时保持其响应性,你需要使用 storeToRefs()。它将为每一个响应式属性创建引用。

import { useUserStore, storeToRefs } from '@/store/user'
export default {
    setup() {
        const user = useUserStore()
        // 使用storeToRefs转化,确保状态响应性
        const userToProps = storeToRefs(user)
        return {
          ...userToProps
        }
    }
}

现在,可以直接在模板中以响应式方式使用状态和动作,例如namechangeName函数。storeToRefs函数确保这些值具有响应性,这意味着当store中的状态改变时,你的组件始终能够显示最新的状态。

<template>
<div>
  <h1>{{ name }}</h1>
  <button @click="changeName('New Name')">Change Name</button>
</div>
</template>

总之,storeToRefs是Pinia的关键特性之一,它使得我们能够在组件中能够直观并且以响应式的方式使用store数据。借助storeToRefs,咱们不需要在组件中引用完整的store,只需要引用我们需要的部分,这使得我们的代码更简洁,易于维护。因此,还是推荐使用storeToRefs在Piniastore和Vue组件之间建立响应式桥梁。

总结

今天咱们学习了一下pinia的基本用法,了解了数据的使用和处理,同时分享了一些使用中的注意, storeToRefs是你在结合使用Pinia和Vue3时的重要工具。最后,希望本文能对你学习pinia有所帮助,可以帮忙点个免费的赞赞嘛,感谢感谢!