Vuex 4.x 模拟实现

7 篇文章 0 订阅
1 篇文章 0 订阅

概要

本文参照vuex 4的基本功能,模拟实现了其主要功能,并提供了关键的代码。

本文是在Vue 3.0上通过其Composition API模拟Vuex 4.0的基本功能。

Vuex的工作流程

在这里插入图片描述
Vuex主要包括Actions,Mutations和State三部分,在4.0后增加了getters,但getters本身只是函数式编程思想的延伸,让组件通过方法来获取state的内容。

Vuex中函数调用流程是组件通过dispatch方法调用Actions中的方法,Actions中的方法通过commit方法,调用Mutations中的方法,由Mutation是中的方法去修改State中的响应式数据,响应式数据的修改会通过Vue的render方法反馈到页面上。

Vuex代码实现流程

(1) 在store.js中, 调用createStore方法,将用户自定义的state, actions, mutations和getters 对象作为参数传入。

import { createStore } from 'vuex'
import state from './state'
import actions from './actions'
import mutations from './mutations'
import getters from './getters'
export default createStore({
  state,actions,mutations, getters
})

(2) 在main.js中,导入createStore返回结果,并通过use方法全局注册。

import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
createApp(App).use(store).mount('#app')

代码模拟实现

通过上面的流程,我们可以看出 createStore 返回了一个store对象,该对象一定包含install方法。
在这里插入图片描述
我们将createStore 打印出来可以看到,store对象包含install方法,我们传入的state,mutations,actions和getters被转换成了_state, _mutations, _actions和getters对象属性。

state

对于_state, 用户的数据是赋值给_state.data, 这样做的好处是如果用户修改响应式数据,vuex并不需要重新调用vue的reactive方法生成响应式数据。
在这里插入图片描述
为了保证store对象的state属性可以被访问,用户并不需要在访问时个加上data的key值,所以为state属性作了一个get方法

在这里插入图片描述

mutations和actions

_mutations和_actions对象中包含我们的自定义方法,但是其并不包含prototype,因为他们的任务只是用来接收用户传入的方法。
在这里插入图片描述

getters

getter对象包含用户传入的方法,并为这些方法增加了get属性。
在这里插入图片描述

代码实现

基于上面的逻辑,createStore 和useStore方法如下:

import { inject } from "vue";
import Store from "./store"
export function createStore(options){
    return new Store(options);
}

export function useStore(){
    const store = inject("store");
    return store;
}
  1. createStore方法接收用户如传入的atcions,mutations,state和getters对象,返回一个Store类的实例。
  2. useStore可以在组件中调用,获取当前的Store类实例,它是通过vue3的inject API实现Store对象的注入。

实现的Store类代码如下:

import { reactive } from "vue";
import { createMutations, createActions, createGetters} from "./creator";
export default class Store{
    constructor(options){
        const {actions, mutations, getters, state} = options;
        this._state = reactive({
            data: state
        });
        const store = this;
        this._mutations = createMutations(mutations, store);
        this._actions = createActions(actions, store);
        this.getters = createGetters(getters, store);
        this.commit = this.commit.bind(store);
        this.dispatch = this.dispatch.bind(store);        
    }
    get state(){
        return this._state.data;
    }
    commit(key, payload){
        this._mutations[key](payload);
    }
    dispatch(key, payload){
        this._actions[key](payload);
    }
    install(app){
        app.provide("store", this) ;
    }
}
  1. Store类的install方法将Store类的实例注册到全局;
  2. Store的类构造方法接收传入的atcions,mutations,state和getters
  3. 调用vue3的reactive方法为{data: state}对象生成响应式数据;
  4. 生成state属性的get方法,用户可以通过调用该get方法直接获取 this._state.data;的值;
  5. 调用createMutations方法创建 this._mutations属性;
  6. 调用createActions方法创建 this._actions属性;
  7. 调用createGetters方法创建 this.getters 属性;
  8. commit方法即根据用户传入的key和参数payload,调用_mutations对象中的指定方法,需要将函数内容的this强制设置为当前Store对象;
  9. dispatch方法即根据用户传入的key和参数payload,调用_actions对象中的指定方法,需要将函数内容的this强制设置为当前Store对象;

createMutations,createActions,createGetters方法,通过调用foreachKeyValue方法,遍历出入的mutations对象,actions对象和getters对象中的方法,将其赋值到Store实例的各个属性中。

export function foreachKeyValue(obj, fn){
    Object.keys(obj).forEach(key => fn(key, obj[key]));
}
export function createMutations(obj, store){
    const _mutations = Object.create(null);
    foreachKeyValue(obj, (key, fn) => {    
        _mutations[key] = function(payload){
            fn.apply(store, [store.state, payload]);
        }
    });
    return _mutations;
}
  1. createMutations方法接收两个参数,一个参数是用户传入的mutations对象,另一个参数是当前Store类的实例;
  2. 创建一个无prototype的_mutations对象;
  3. 调用foreachKeyValue方法,遍历参数mutations对象的所有用户自定义方法,按照相同的key,在_mutations上创建一个函数,该方法通过apply调用用户自定义方法,并将用户自定义方法的this限定为当前Store类实例,传入当前的state和用户自己的参数。
export function createActions(obj, store){
    const _actions = Object.create(null);
    foreachKeyValue(obj, (key, fn) => {    
        _actions[key] = function(payload){
            fn.apply(store, [store, payload])
        }
    });
    return _actions;
}
  1. createActions方法接收两个参数,一个参数是传入的actions对象,另一个参数是当前Store类的实例;
  2. 创建一个无prototype的_actions 对象;
  3. 调用foreachKeyValue方法,遍历参数actions对象的所有用户自定义方法,按照相同的key,在_actions上也创建一个方法,该方法通过apply调用用户自定义方法,并将用户自定义方法的this限定为当前Store类实例,传入当前的Store类实例和用户自己的payload参数。
export function createGetters(getters, store){
    const _getters = {}
    foreachKeyValue(getters, (key, fn) =>{
        Object.defineProperty(_getters, key, {
            get: ()=> fn(store.state, getters)
        });
    });
    return _getters;
}
  1. createGetters方法接收两个参数,一个参数是传入的getters对象,另一个参数是当前Store类的实例;
  2. 创建_getters 对象;
  3. 调用foreachKeyValue方法,遍历参数getters对象的所有用户自定义方法,按照相同的key,在_getters 上创建自定义属性,在该属性的get方法中调用用户的自定义方法,将state和getters对象作为参数一并传入。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值