Pinia
Pinna 是 Vue 的状态管理库,支持跨组件、页面共享状态。同时支持 vue2 和 vue3。
和 vuex 的区别
- 支持组合式 API
- 可搭配 TypeScript 使用,提供可靠的类型推断
- mutation 已被弃用
- actions 中支持同步和异步方法修改 state 状态
- 每一个 store 仓库都是独立的、扁平化的(不再像 vuex 中的 modules 嵌套),store 之间可以相互调用
- 更加轻量,压缩之后体积只有 1kb 左右
选项式 API 的写法
import { defineStore } from 'pinia';
const useCounterStore = defineStore('counter', {
state: () => ({
count: 1
}),
getters: {
doubleCount: state => state.count * 2
},
actions: {
increment() {
this.count++;
}
}
});
export default useCounterStore;
组合式 API 的写法
import { ref, computed } from 'vue';
import { defineStore } from 'pinia';
const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
function increment() {
count.value++;
}
return { count, doubleCount, increment };
});
export default useCounterStore;
在组件中使用:
import useCounterStore from '@/stores/counter';
const counterStore = useCounterStore();
console.log(counterStore);
console.log(counterStore.count);
counterStore 的打印结果是一个 Proxy 对象,包括 $dispose
、$id
、$onAction
、$patch
、$reset
、$subscribe
、$state
、_hotUpdate
、_isOptionsAPI
等属性和方法,还包括自己在 store 中定义的 count
、increment
。所以在访问变量时不能写成counterStore.state.count
修改数据
修改数据的方式有三种:
- 直接修改 state 的值,如
counter.count++
- 使用
$patch
方法,可以在同一时间更改多个属性 - 调用 actions 中的方法,如
counter.increment()
import useCounterStore from '@/stores/counter';
const counter = useCounterStore();
counter.count++;
counter.$patch({ count: counter.count + 1 });
counter.increment();
数据解构
下面的方式会丢失响应性:
import useCounterStore from '@/stores/counter';
const { count } = useCounterStore();
可以用 toRefs()
,但是代价很大,会把所有属性都变为 ref 包裹。
所以官方推出 storeToRefs
这个 API,创建一个引用对象,包含 store 的所有 state、 getter 和 plugin 添加的 state 属性。 类似于 toRefs()
,但专门为 Pinia store 设计, 所以 method 和非响应式属性会被完全忽略。
import { storeToRefs } from 'pinia';
import useCounterStore from '@/stores/counter';
const counter = useCounterStore();
const { count } = storeToRefs(counter);
订阅 state
可以通过 store 的 $subscribe()
方法侦听 state 及其变化。
如果添加第二个参数:{ detached: true }
,则表示当前组件被卸载时,订阅不会被删除
counter.$subscribe((mutation, state) => {
// 每当状态发生变化时,将整个 state 持久化到本地存储。
localStorage.setItem('count', JSON.stringify(state));
});
tip
可以在组件中使用 watch()
函数侦听整个 state。
import useCounterStore from '@/stores/counter';
import { watch } from 'vue';
const counter = useCounterStore();
watch(
() => ({ ...counter.$state }), // 侦听整个 state
(newState, oldState) => {
console.log('New State:', newState);
console.log('Old State:', oldState);
},
{ deep: true } // 深度监听
);