pinia是vue的状态管理库。它是一个vue的插件。让我们简单的实现它。
createPinia
我们这样引入它:
import { createPinia } from 'pinia';
app.use(createPinia());
由此,我们可知:createPinia方法的返回值是:一个拥有 install()
方法的对象。所以createPinia函数可以写为:
const createPinia = () => {
const install = () => { };
return {
install
}
}
在pinia官网中有这么一句话:创建一个 pinia(根存储)并将其传递给应用程序。所以修改以上代码为:
import { reactive } from 'vue';
const createPinia = () => {
const rootStore = reactive({}); // 保存所有的store
// 用于将注册的store添加的rootStore上的方法
const setRootStore = (name, store) =>{
// 如果name不存在则添加
if(!rootStore[name]) {
rootStore[name] = store;
}
return rootStore;
}
const install = (app) => {
app.provide('setRootStore', setRootStore); // 将setRootStore提供给种鸽应用
};
return {
install
}
}
defineStore
我们一般这样使用它:
import { defineStore } from 'pinia';
const useStore = defineStore('store', {
state: () => ({
name: 'pinia',
}),
getters: {
getName() { return this.name; }
},
actions: {
setName(name) { this.name = name; }
}
})
// =======================================================
import { useStore } from './store';
const store = useStore();
const setNameHandle = () => { store.setName('名字'); }
由此,我们可知:defineStore函数接收两个参数:
1. 字符串,表示当前store的名称;
2. 对象,配置state,getters,actions
它的返回值是一个函数,这个函数执行之后,会得到useStore中的state,getters,actions,并且它们都是响应式的,所以defineStore函数可以写为:
import { reactive, toRef, computed } from 'vue';
const defineStore = (name, { state, getters, actions } = options) => {
const store = {}
// 将state上的属性转化为响应式
if(state && typeOf state === 'funtion') {
const _state = state();
store.$state = reactive(_state); // 保存this
for(let key in _state) {
store[key] = toRef(store.$state, key);
}
}
// 将getters转化为计算属性
if(getters && Object.keys(getters).length > 0) {
for(let getter in getters) {
// bind中的第一个参数是this指向,第二个参数是getters的方法中的参数
store[getter] = computed(getters[getter].bind(store.$state, store.$state))
}
}
// 将actions中的方法添加到store上
if(actions && Object.keys(actions).length > 0) {
for(let method in actions) {
store[method] = actions[methos];
}
}
return () => {
return reactive(store);
}
}
以上代码为单个的store,我们现在需要将单个的store添加到rootStore上去,并且给它添加一个修改state的方法:$patch。
import { reactive, toRef, computed, inject } from 'vue';
const defineStore = (name, { state, getters, actions } = options) => {
const store = {}
// 将state上的属性转化为响应式
if(state && typeOf state === 'funtion') {
const _state = state();
store.$state = reactive(_state); // 保存this
for(let key in _state) {
store[key] = toRef(store.$state, key);
}
}
// 将getters转化为计算属性
if(getters && Object.keys(getters).length > 0) {
for(let getter in getters) {
// bind中的第一个参数是this指向,第二个参数是getters的方法中的参数
store[getter] = computed(getters[getter].bind(store.$state, store.$state))
}
}
// 将actions中的方法添加到store上
if(actions && Object.keys(actions).length > 0) {
for(let method in actions) {
store[method] = actions[methos];
}
}
return () => {
const setRootStoreHanle = inject('setRootStore'); // 得到setRootStore方法
const rootStore = setRootStoreHandle(name, reactive(store)); // 将store添加的rootStore上
const currentStore = rootStore[name];
currentStore.$patch = patch; // 添加patch方法
return currentStore;
}
}
function patch(value) {
for(let key in value) {
this[key] = value[key];
}
}
这样,一个及其简单的pinia就完成了。