pinia
主要包括以下五部分,经常用到的是 store、state、getters、actions
以下使用说明,注意事项,仅限于 vue3 setup
语法糖中使用,若使用选项式 API
请直接查看官方文档:
一、前言:
pinia
是为了探索 vuex
下一次迭代是要实现那些功能用途,pinia
已实现vuex5
的绝大部分功能;
并且与 Vuex
相比,Pinia
提供了一个更简单的 API
,具有更少的规范,提供了 Composition-API 风格的 API
,最重要的是,在与 TypeScript
一起使用时具有可靠的类型推断支持;
二、pinia 与vuex <= 4.x 的差异
1、****mutations
不再存在。他们经常被认为是 非常 冗长。他们最初带来了 devtools
集成,但这不再是问题。
**2、**无需创建自定义复杂包装器来支持 TypeScript
,所有内容都是类型化的,并且 API
的设计方式尽可能利用 TS
类型推断。
**3、**不再需要注入、导入函数、调用函数、享受自动完成功能
!
4、****无需动态添加 Store
,默认情况下它们都是动态的,您甚至都不会注意到。请注意,您仍然可以随时手动使用 Store 进行注册,但因为它是自动的,您无需担心。
**5、**不再有 modules
的嵌套结构。您仍然可以通过在另一个 Store 中导入和 使用
来隐式嵌套 Store
,但 Pinia
通过设计提供平面结构
,同时仍然支持 Store 之间的交叉组合方式
。 您甚至可以拥有 Store 的循环依赖关系。
**6、**没有 命名空间模块。鉴于 Store
的扁平架构,“命名空间” Store
是其定义方式所固有的,您可以说所有 Store
都是命名空间的。
三、store:
store:它持有未绑定到您的组件树的状态和业务逻辑
;托管全局状态
像一个始终存在并且每个人都可以读取和写入的组件;
主要有三个方法:state、getters、actions
,类似于组件中数据、计算属性、方法;
用于存储不同组件直接共享的数据实例方法,以及页面之间需要保留的数据状态;
// count.ts 文件
<script lang="ts">
import { defineStore } from 'pinia'
// defineStore 的第一个参数是 唯一标识ID 用于关联 devtool 调试使用
// 第二个参数是 一个对象 包含 state、actions,gettes
// 声明的 属性useCount 建议以 use 开头,保持书写的统一性
export const useCount = defineStore('count', {state:() => {return{}},actions: {},gettes: {}
})
</script>
在组件中使用:
注意:若 解构使用 store 中的属性 方法,需要使用 storeToRefs()
或者 toRefs()
让其保持响应式
<script setup>import { toRefs } from 'vue'import { storeToRefs } from 'pinia'import { useCount } from '@/store'const count = useCount()// 这样解构获取 store 中属性方法,会丢失响应式const { num } = count// 1、使用 pinia自带的storeToRefs(), 将store中属性转换为 ref 数据以保持响应式const { doubleCountAdd } = storeToRefs(count)console.log('=doubleCountAdd==', doubleCountAdd)// 2、使用vue3 的 toRefs() 转化为 ref 响应式数据const { doubleCount } = toRefs(count)console.log('=doubleCount==', doubleCount)
</script>
四、state:
state: 类似组件中的 data(){return{}}
,但是在 pinia 中的state 建议书写为:
使用箭头函数,用于完整推断类型
state: () => {return {name: 'Andy',num: 0}
}
组件中使用:
<script setup lang='ts'>import { useCount } from '@/store'const count = useCount()// 1、直接调用或者修改console.log(count.name)// 2、通过$patch({}) 同时修改多个属性count.$patch({name: '刺客',num++})// 或者传入一个回调函数count.$patch((state) => {state.count = '4'})
</script>
五、actions:
actions 类似组件中的methods
,可以在组件中直接调用里面的方法
// count.ts 文件
<script lang="ts">
export const useCount = defineStore('count', {state: () => {return{name: 'Andy',num: 0}},actions: {add() {// 直接通过 this 调用 state 中的属性,也可以调用其他 store 中属性,只需引入即可this.num++},},
})
</script>
组件中可以直接通过 调用 add()
方法来修改 num
<script setup>import { useCount } from '@/store'const count = useCount()count.add()
</script>
六、gettes:
相当于组件中的 computed
计算属性:
// count.ts 文件
<script lang='ts'>
import { defineStore } from 'pinia'
export const useCount = defineStore('count', {state: () => {return{name: 'Andy',num: 0}},getters: {// 相当于组件中的 计算属性doubleCount(state): number {return state.num * 2},doubleCountAdd():number {// 可以在其他 getter 中直接调用另一个getterreturn this.doubleCount + 1},// 接收额外参数时,需要返回一个函数处理doubleCountAdd2:(state) => {return (num:number):number => state.num * num} }
})
</script>
在组件中可以直接使用
<script setup>
import { useCount } from '@/store'
const count = useCount()
console.log(count.doubleCountAdd)
count.$patch({name: '刺客',num: 3
})const doubleCountAdd2 = count.doubleCountAdd2(8)// 上面state.num 值为 3, 传入 额外参数 为8,故最后为 3* 8 = 24
</script>
完整代码如下:
// count.ts 文件
import { defineStore } from 'pinia'
// 通过 defineStore 定义的 store 第一个参数 count 是唯一的id,用于链接devtool
// 定义 一个id 为count的 store export const useCount = defineStore('count', {state: () => {return{name: 'Andy',num: 0}},actions: {add() {this.num++},},// getter 只会依赖状态getters: {// 相当于组件中的 计算属性doubleCount(state): number {return state.num * 2},doubleCountAdd():number {// 可以在其他 getter 中直接调用另一个getterreturn this.doubleCount + 1},// 接收额外参数,返回一个函数处理doubleCountAdd2:(state) => {return (num:number):number => state.num * num} },// 若不需要额外配置,// persist: true,// 额外配置persist: {// key: 'piniaStore', //存储名称// storage: sessionStorage, // 存储方式 默认存储在localStorage// paths: ['name'], //指定 state 中哪些数据需要被持久化。[] 表示不持久化任何状态,undefined 或 null 表示持久化整个 state}
})
// main.ts 文件
import { createApp } from 'vue'
import { createPinia } from 'pinia'
const app = createApp(App)
const pinia = createPinia()
//导入pinia 持久化 插件
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
pinia.use(piniaPluginPersistedstate)
app.use(pinia)
app.mount('#app')
// 单文件组件 myPinia/index.vue 文件中使用
<template><div class="myPinia">This is a text demo of the pinia.<hr><div>count.num: {{ count.num }}</div><div>count.doubleCount: {{ count.doubleCount }}</div><div>count.doubleCountAdd: {{ count.doubleCountAdd }}</div><div>num: {{ num }}</div><div>doubleCountAdd: {{ doubleCountAdd }}</div><div>doubleCount: {{ doubleCount }}</div><div>doubleCountAdd2: <span>{{ doubleCountAdd2 }}</span></div><button @click="count.add()">add</button></div>
</template><script setup>
import { toRefs } from 'vue'
import { storeToRefs } from 'pinia'
import { useCount } from '@/store'
const count = useCount()
console.log('==count==', count)
// 解构获取 store 中属性方法,不是响应式
const { num } = count
// 1、使用 pinia自带的storeToRefs(), 将store中属性转换为 ref 数据以保持响应式
const { doubleCountAdd } = storeToRefs(count)
console.log('=doubleCountAdd==', doubleCountAdd)
// 2、使用vue3 的 toRefs() 转化为 ref 响应式数据
const { doubleCount } = toRefs(count)
console.log('=doubleCount==', doubleCount)
// 通过 $patch 修改state 中多个属性
count.$patch({name: '刺客',num: 3})// 传入额外参数const doubleCountAdd2 = count.doubleCountAdd2(8) // 上面state.num 值为 3, 传入 额外参数 为8,故最后为 3* 8 = 24
</script><style lang="scss" scoped>div{font-size: 18px;color: #333;span {color: red;}
}
</style>