简介
本质是一个插件,基于reactive实现响应式仓库(全局共享)(可以先看响应式原理)
Pinia & Vuex
- vuex:
- ts兼容性不好
- 命名空间的缺陷(只能有一个store)
- mutation和action有区别
- pinia:
- 更简洁的API
- ts兼容性更好
- 无命名空间的缺陷(可以创建多个store)
- 删除了mutation,统一在action中开发
使用方法
引入
import { createApp } from "vue";
import App from "./App.vue";
import { createPinia } from "@/my-pinia";
const app = createApp(App);
const pinia = createPinia()
console.log("createPinia", createPinia);
app.use(pinia);
app.mount("#app");
创建store
import { reactive, computed, toRefs } from "vue";
import { defineStore } from "@/my-pinia";
export const useCountStore = defineStore("count", () => {
const state = reactive({
count: 0,
});
const doubleCount = computed(() => state.count * 2);
const addCount = () => state.count++;
return {
...toRefs(state),
doubleCount,
addCount,
};
});
页面调用
<script setup>
import { useCountStore } from "./stores/count";
const store = useCountStore();
</script>
<template>
<div>
{{ store.count }}
<div>原数:{{ store.count }} getters:{{ store.doubleCount }}</div>
<button @click="store.addCount">增加</button>
</div>
</template>
核心实现
- 通过在app中注入一个对象
pinia.state
,触达每一个子组件,在定义时给state
追加store
。
- 在获取时通过
inject
将store
传入组件中。
createPinia.js : 创建插件并注入
- 管理state及其下的store:
- 基于
effectScope
生成scope
,scope
管理state
,state
内部存放所有的store
,用于批量管理其中的响应式数据(控制响应式数据是否刷新视图)。
- 每个
store
内部也有一个scope
,管理内部的属性是否刷新视图。
- 注入
pinia
:通过provide
将pinia
注入到app
上,各组件实例可以获取到该pinia
import { markRaw, effectScope, ref } from "vue";
import { symbolPinia } from "./rootStore";
export function createPinia() {
const scope = effectScope(true);
const state = scope.run(() => ref({}));
const pinia = markRaw({
install(app) {
app.provide(symbolPinia, pinia);
app.config.globalProperties.$pinia = pinia;
pinia._a = app;
},
_a: null,
_e: scope,
_s: new Map(),
state,
});
return pinia;
}
defineStore.js : 创建store
- 每一个
store
都是一个响应式对象reactive
import {
effectScope,
getCurrentInstance,
inject,
reactive,
computed,
toRefs,
} from "vue";
import { symbolPinia } from "@/my-pinia/rootStore.js";
export function defineStore(idOrOptions, setup) {
let id;
let options;
if (typeof idOrOptions == "string") {
id = idOrOptions;
options = setup;
} else {
id = idOrOptions.id;
options = idOrOptions;
}
const isSetupStore = typeof setup === "function";
function useStore() {
const currentInstant = getCurrentInstance();
const pinia = currentInstant && inject(symbolPinia);
if (!pinia._s.has(id)) {
if (isSetupStore) {
createSetupStore(id, options, pinia);
} else {
createOptionStore(id, options, pinia);
}
}
const store = pinia._s.get(id);
return store;
}
return useStore;
}
createSetupStore : 根据传入的函数返回store
function createSetupStore(id, setup, pinia) {
let store = reactive({});
let scope;
const setupScope = pinia._e.run(() => {
scope = effectScope();
return scope.run(() => setup());
});
function wrapAction(name, action) {
return function () {
return action.apply(store, arguments);
};
}
for (let key in setupScope) {
let prop = setupScope[key];
if (typeof prop === "function") {
setupScope[key] = wrapAction(key, prop);
}
}
Object.assign(store, setupScope);
pinia._s.set(id, store);
return store;
}
createOptionStore(建议写法) :根据传入的配置返回store
- 将选项配置整合一下再调用
createSetupStore
function createOptionStore(id, options, pinia) {
let { state, getters, actions } = options;
let store = reactive({});
function setup() {
pinia.state.value[id] = state ? state() : {};
const localStore = toRefs(pinia.state.value[id]);
return Object.assign(
localStore,
actions,
Object.keys(getters).reduce((computedGetters, name) => {
computedGetters[name] = computed(() => {
return getters[name].call(store, store);
});
return computedGetters;
}, {})
);
}
store = createSetupStore(id, setup, pinia);
return store;
}
主文件(lib/index.js)
export { createPinia } from "./createPinia";
export { defineStore } from "./defineStore";
export const symbolPinia = Symbol();
其余方法[补充]
-
$patch
:批量更改store中的属性,本质上是合并对象(深拷贝)
-
$reset
:重置store中的state为初始值(保存刚开始的值,调用时覆盖即可)
-
$subscribe
:监听对应store中state所有的属性,当属性变化时触发回调watch(()=>store)
-
$onAction
:监听store中的actions,当调用actions时触发回调(发布订阅,在wrapAction中发布)


-
$dispose
:删除store(停止收集依赖,视图不根据数据更新了[effectScope.stop])
-
mapHelpers(辅助函数,只能用于vue2)
mapState
:
mapAction
: