深入浅出 Pinia:革新 Vue 状态管理的利器 ⚡

什么是pinia?

官方解释:Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。

说白了就相当于一个数据储存库,开发者可以将其内部储存的数据应用到各个组件上。pinia对于部分小型项目来说有时候是多此一举,但是对于中大型项目来说是不可或缺的,利用pinia可以很好的解决组件之间状态共享和管理等一系列麻烦。(其前身是Vuex,这里就不过多赘述了)

使用 pinia 的好处

优胜劣汰是自然法则,其同样适用于项目,每个库或工具都有其存在的价值,而pinia也是有一定优点才会被开发者使用。

  • 直观易用的API:pinia提供了state(状态)、getter(计算属性)、action(业务逻辑),抛弃了Vuex中的Mutation。
  • 模块化设计:可以创建多个 store,并且将其分割成不同的模块,有利于大型项目的组织和维护。
  • 轻量级:Pinia 库本身非常轻量,对应用性能影响极小。
  • 良好的 TypeScript 支持:对 TypeScript 的支持非常好,提供了完全类型化的 API。
  • 兼容性好:对于 Vue 3 和 Vue 2 都支持。
  • 插件系统:Pinia 允许开发者扩展其功能。

当然其优点远远不止这些,读者可以在开发时自行体会。

pinia 的基本使用

一、安装 pinia

bash 复制代码
npm install pinia 
# 或者
yarn add pinia

将pinia挂载到Vue上,并且创建一个pinia实例(store 根储存):

js 复制代码
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import './style.css'
import App from './App.vue'

const app = createApp(App)
const pinia = createPinia();
app
    .use(pinia)
    .mount('#app')

二、创建 store

这里创建 store 其实是创建一个用于集中管理和保存应用全局状态的仓库,并且我们需要 pinia 提供的defineStore()方法来创建一个 store ,其用来存放我们需要全局使用的数据。

具体一般是在 src 文件夹中创建一个 store 文件夹用于存放我们创建的 store,在其目录下就可以新建各种需要的 store 了。例如:创建一个存放user数据的store。

js 复制代码
// src/store/user.js

import { defineStore } from 'pinia'

// 第一个参数是应用程序中 store 的唯一 id
export const useUserStore = defineStore('user', () => {
    // 其他配置...
})

defineStore的第二个参数可以接收两种值:Setup 函数或 Option 对象。

setup 函数

其与 Vue 组合式 API 的 setup 函数 很相似,传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。例如:

js 复制代码
export const useUserStore = defineStore('user', () => {
  const count = ref(0);
  const doubleCount = computed(() => count.value * 2);
  
  function increment() {
    count.value++;
  }

  return { 
      count,
      doubleCount,
      increment,
  }
})
Option 对象

其与 Vue 的选项式 API 类似,传入一个带有 stateactionsgetters 属性的对象。例如:

js 复制代码
export const useUserStore = defineStore('user', {
  // 可以将 state 看作是组件的data选项,返还一个带有你的状态的对象
  state: () => ({ 
      count: 0, 
      name: 'xixili', 
  }),
  
  // getter 是 state 的计算属性,可以衍生出一些状态,并且其接收 state 作为参数
  getters: {
    doubleCount: (state) => state.count * 2
  },
  
  // actions 用来执行状态更改的函数,可以是同步的,也可以是异步的
  actions: {
    increment() {
      this.count++;
    },
  },
})

这两种用法各有各的优势和劣势,挑选自己喜欢的使用即可。


三、使用 store

定义完 store ,接下来就是在需要的组件内调用即可。

html 复制代码
<script setup>
import { useUserStore } from '../store/user.js'
// 这样可以在组件中的任意位置访问 `store` 变量
const userStore = useUserStore();
</script>

实战实例:

安装完并挂载后就可以开始操作了,在 store 文件夹内部创建counter.js

js 复制代码
// counter.js

import { defineStore } from 'pinia'
import { ref } from 'vue'

// 仓库名 函数
export const useCounterStore = defineStore('counter', () => {
    const count = ref(0);

    function increment() {
        count.value++; 
    }
    return {
        count,
        increment,
    }
})

为了体现一个 store 可以在多个组件内同时使用,分别创建CompA.vueCompSubA.vue.

html 复制代码
<!-- CompSubA.vue -->
<template>
    <div>
        CompSubA
        {{ count }}
        <hr>
        {{ counterStore.count }}
    </div>
</template>

<script setup>
import { toRefs } from 'vue';
import { useCounterStore } from '../store/counter';
const counterStore = useCounterStore(); // 本地和中央连接的过程
const { count } = toRefs(counterStore);
// const { count } = counterStore(); 解构
</script>

<style  scoped>

</style>

注: 注释中的解构是没有问题的,但是这样就丢失了响应式,如果还要保持响应式,就需要toRefs方法。

html 复制代码
<!-- CompA.vue -->

<template>
    <div>
        <h2>CompA</h2>
        <p>count: {{ counterStore.count }}</p>
        <button @click="counterStore.increment">Add</button>
        <CompSubA />
    </div>
</template>

<script setup>
import CompSubA from './CompSubA.vue';
// 引入中央模块
import { useCounterStore } from '../store/counter';
const counterStore = useCounterStore();
</script>

<style scoped>

</style>

最后呈现的效果为:

并且其支持开发者工具Vue Devtools,并且可以手动修改调试数据。

相关推荐
浏览器API调用工程师_Taylor10 分钟前
自动化重复任务:从手动操作到效率飞跃
前端·javascript·爬虫
赵润凤19 分钟前
Vue 高级视频播放器实现指南
前端
FogLetter34 分钟前
从原生JS事件到React事件机制:深入理解前端事件处理
前端·javascript·react.js
小公主1 小时前
如何利用闭包封装私有变量?掌握防抖、节流与 this 问题的巧妙解决方案
前端
烛阴1 小时前
JavaScript 的动态魔法:使用 constructor 动态创建函数
前端·javascript
前端 贾公子1 小时前
tailwind ( uni ) === 自定义主题
前端
独立开阀者_FwtCoder1 小时前
大制作!在线 CSS 动效 编辑神器!太炫酷了!
前端·javascript·github
白白李媛媛1 小时前
vue3中实现echarts打印功能
前端·vue.js·echarts
尘心cx1 小时前
前端-HTML-day2
前端·html
歘chua1 小时前
组件封装:封装一个可复用的crud界面的思路
前端