pinia
Pinia读作皮尼亚, 是 Vue 的存储库,它允许您跨组件/页面共享状态。在vue2的时代我们更多的是使用vuex进行全局管理,但是vue3已经全面拥抱pinia了
基本示例
其实在我们使用create-vue脚手架创建好的项目里已经帮我们写好了一个基本示例,位于\src\stores\counter.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})上面的代码为了我们演示了如何创建一个store,你可以理解为定义一个全局可以使用的状态
然后我们就可以在其它的组件/页面里使用它
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()示例
页面一
<template>
<div>
我是页面一,store的值是:{{ counter.count }}
</div>
<el-button @click="test">数量自增并跳转到页面2 </el-button>
</template>
<script lang="ts" setup>
import { ElButton } from 'element-plus'
import { useCounterStore } from '@/stores/counter'
import { useRouter } from 'vue-router';
const router = useRouter()
const counter = useCounterStore();
const test = () => {
counter.increment();
router.push({ name: 'test2' })
}
</script>页面二
<template>
<div>
我是页面二,store的值是:{{ counter.count }}
doubleCount:{{ counter.doubleCount }}
</div>
</template>
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>命名规范
首先Store 是使用 defineStore() 定义的,并且它需要一个唯一名称,作为第一个参数传递:
import { defineStore } from 'pinia'
// useStore 可以是 useUser、useCart 之类的任何东西
// 第一个参数是应用程序中 store 的唯一 id
export const useStore = defineStore('name', {
// other options...
})这个 name,也称为 id 将返回的函数命名为 use... 是跨可组合项的约定,以使其符合你的使用习惯。
一个完整的store是由state,getters,actions组成的
State
拿我们上面的基本示例代码举例
const count = ref(0)我们使用ref定义的count变量就可以理解为是pinia的state
访问state
默认情况下,我们可以通过 store 实例访问状态来直接读取和写入状态:
const counter = useCounterStore()
counter.count++批量修改state
除了直接用 store.counter++ 修改 store,你还可以调用 $patch 方法。 它允许您使用部分“state”对象同时应用多个更改:
store.$patch({
counter: store.counter + 1,
name: 'Abalam',
})但是,使用这种语法应用某些突变非常困难或代价高昂:任何集合修改(例如,从数组中推送、删除、拼接元素)都需要您创建一个新集合。 正因为如此,$patch 方法也接受一个函数来批量修改集合内部分对象的情况:
cartStore.$patch((state) => {
state.items.push({ name: 'shoes', quantity: 1 })
state.hasChanged = true
})getters
示例代码里
const doubleCount = computed(() => count.value * 2)这个用计算属性定义的doubleCount就是一个getters,它和计算属性一样,也是只读并且具有缓存的
将参数传递给 getter
Getters 只是幕后的 computed 属性,因此无法向它们传递任何参数。 但是,您可以从 getter 返回一个函数以接受任何参数:
const test_arr = ref([{
name: '李雷',
id: 1
}, {
name: '韩梅梅',
id: 2
}])
const getUserById = computed(() => (id: number) => test_arr.value.find((f) => f.id === id)?.name)并在组件中使用:
<div>id1的name是:{{ counter.getUserById(1) }}</div>
<div>id2的name是:{{ counter.getUserById(2) }}</div>请注意,在执行此操作时,getter 不再缓存,它们只是您调用的函数。 但是,您可以在 getter 本身内部缓存一些结果,这并不常见,但应该性能更高:
const count = ref(0);
const test_arr = ref([{
name: '李雷',
id: 1
}, {
name: '韩梅梅',
id: 2
}])
const getUserById = computed(() => (id: number) => test_arr.value.find((f) => f.id === id)?.name+count.value)Actions
Actions 相当于组件中的函数。 它们非常适合定义业务逻辑:
示例代码里
function increment() {
count.value++
}这个自增函数就是一个actions,它的内部可以对某些state做赋值操作,最重要的是actions内部支持异步操作