什么是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
npm install pinia 
# 或者
yarn add pinia
将pinia挂载到Vue上,并且创建一个pinia实例(store 根储存):
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。
// src/store/user.js
import { defineStore } from 'pinia'
// 第一个参数是应用程序中 store 的唯一 id
export const useUserStore = defineStore('user', () => {
    // 其他配置...
})
defineStore的第二个参数可以接收两种值:Setup 函数或 Option 对象。
setup 函数
其与 Vue 组合式 API 的 setup 函数 很相似,传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。例如:
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 属性的对象。例如:
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 ,接下来就是在需要的组件内调用即可。
<script setup>
import { useUserStore } from '../store/user.js'
// 这样可以在组件中的任意位置访问 `store` 变量
const userStore = useUserStore();
</script>
实战实例:
安装完并挂载后就可以开始操作了,在 store 文件夹内部创建counter.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.
<!-- 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方法。
<!-- 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,并且可以手动修改调试数据。