什么是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 类似,传入一个带有 state
、actions
与 getters
属性的对象。例如:
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.vue
和CompSubA.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
,并且可以手动修改调试数据。
