Pinia 和 Vue Router 一样是 vue3 官方网站是推荐的官方库。

# 一、Pinia 简介

# 1、发展史

  Pinia 起始于 2019 年 11 月左右的一次实验,其目的是设计一个拥有组合式 API 的 Vue 状态管理库。从那时起,我们就倾向于同时支持 Vue 2 和 Vue 3。

  2020 年 9 月 18 日,Vue.js 发布 3.0 版本,其中最大的改变就是加入的组合式 API。

  2021 年 3 月 2 日,Pinia 作者 在 Vue 官方仓库发起pull 请求 (opens new window),并作出了如下介绍:

  • Vue2 和 Vue3 都支持
  • 去掉了 mutations 🤔
  • 没有命名空间(即不需要 modules)🤔,采用扁平式的设计方式
  • 完美的支持 TypeScript

  2021 年 3 月 30 日,该作者宣称:Pinia 成为 Vue 的下一个官方状态管理库。

  当然,现在 Pinia 已经纳入 vue 官方账户下了:Pinia (opens new window) (作者在个人推特上发推说明了)

# 2、核心思想

  Pinia 从使用的角度和 Vuex 几乎是一样的,但却比 Vuex 更简单了。

  Vuex 团队 在 github 上声称:Pinia 与 Vuex 5 几乎完全相同或增强的 API。你可以简单地将 Pinia 视为具有不同名称的 Vuex 5

  根据 vuejs 的Discussions (opens new window)的信息,可以发现:Pinia 是由 vue.js 的核心团队成员@posva (opens new window) 制作的,Vuex 5 在很大程度上受到 Pinia 的启发。👍

# 3、优点汇总 ✨

  从开发角度来讲,其优秀的智能提示让开发体验感拉满。

去掉了 mutations 🤔 action 一家独大
没有命名空间(即不需要 modules)🤔 扁平式设计、可以创建多个 store
完美的支持 TypeScript 专为 Typescript 设计
状态管理是响应式的 可以直接操作模块里的 state
支持插件扩展自身功能
支持服务端渲染
同时支持 vue2 和 vue3

# 二、Pinia 使用

# 1、简介

  相较于 vuex,Pinia 没有复杂的概念。你可以这样简单的理解:

理解

  选项式写法中:

Pinia 中的 state、getter 和 action,对应于 组件中的 data 选项、 computed 选项 和 methods 选项

  组合式写法中:

Pinia 中的 state、getter 和 action,对应于 组件中的 ref()函数、computed()函数、function()函数

# 2、安装配置

安装:

npm install pinia

构建 store:

  • store / index.ts
import { createPinia } from 'pinia'

// 大佬pinia产生了✍
export default createPinia()

全局使用:

  • main.ts
import { createApp } from 'vue'
import App from './App.vue'

// import { createPinia } from 'pinia'
// const pinia = createPinia()
import pinia from './store'

const app = createApp(App)

app.use(pinia) // 插件注册成功(vue中能使用pinia了)
app.mount('#app')

# 3、Store 对象 ✨

  经过上面的全局注册后,我们在 store 文件夹下,创建的每一个文件都可以作为 Store 对象

提示

  defineStore() 的第一个参数是一个独一无二的名字,用它来连接 store 和 devtools

  并且,defineStore()返回的是一个函数,命名规则为 useXXX

选项式写法 😄

  • store / useCounter.ts
import { defineStore } from 'pinia'

// 第二个参数:是一个Option 对象
const useCounterStore = defineStore('counter', {
  state() {
    return {
      count: 0
    }
  },
  getters: {
    double(state) {
      return state.count * 2
    }
  },
  actions: {
    increment() {
      this.count++
    }
  }
})

export default useCounterStore
组合式写法
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

// 第二个参数:是一个Setup 函数
const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
    // console.log(count.value)
  }

  return { count, doubleCount, increment }
})

export default useCounterStore

# 4、使用

  下面以使用 setup()的方式为了:

不使用 setup()写法:官方描述 (opens new window)

<template>
  <div>
    你好,我是pinia ---{{ counterStore.count }}
    <button @click="counterStore.increment()">加1</button>
  </div>
</template>

<script setup>
import useCounterStore from './stores/counter'

const counterStore = useCounterStore()
</script>

  可以看到我们在使用 getters 时,并没有加上.value

响应式 ✍ 与 storeToRefs

  store 是一个用 reactive 包装的对象,所以不用加上.value

  并且我们还不能对 store 进行解构,因为这样会丢失响应式(这就和直接解构 props 效果一样):

<script setup>
import useCounterStore from './stores/counter'

const counterStore = useCounterStore()

// count、doubleCount 将始终是 0
const { count, doubleCount } = counterStore
</script>

  解决方案:

<script setup>
import useCounterStore from './stores/counter'
import { storeToRefs } from 'pinia'

const counterStore = useCounterStore()

const { count, doubleCount } = storeToRefs(counterStore)
// const { increment } = counterStore // 此时 action 可以直接被解构
</script>

# 5、脚手架

  我们使用基于 vite 的构建工具项目 create-vue 创建的项目,是有 Pinia 选项的,选择 Pinia 后会在项目中自动集成。

更新于 : 7/8/2024, 10:21:14 AM