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 后会在项目中自动集成。