• Vuex 4.x 模拟实现


    概要

    本文参照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
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

    import { createApp } from 'vue'
    import App from './App.vue'
    import store from './store'
    createApp(App).use(store).mount('#app')
    
    • 1
    • 2
    • 3
    • 4

    代码模拟实现

    通过上面的流程,我们可以看出 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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    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]));
    }
    
    • 1
    • 2
    • 3
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1. createGetters方法接收两个参数,一个参数是传入的getters对象,另一个参数是当前Store类的实例;
    2. 创建_getters 对象;
    3. 调用foreachKeyValue方法,遍历参数getters对象的所有用户自定义方法,按照相同的key,在_getters 上创建自定义属性,在该属性的get方法中调用用户的自定义方法,将state和getters对象作为参数一并传入。
  • 相关阅读:
    程序化交易(一)交易接口接入
    大数据管理平台有什么用?如何利用大数据管理平台优化企业运营?
    中国式现代化落地社区的“3510”模式示范点在烟台正式启动
    07 信息不等式
    【数据分享】全国县市2000-2020年医疗卫生机构床位数数据(excel和shp格式)
    RabbitMq-监控管理
    STM32 定时器介绍
    Opencv 图像处理:数字图像的必会知识
    算法小讲堂之哈希表|散列表|考研笔记
    【Vue2.x源码系列04】依赖收集原理(Dep、Watcher、Observer)
  • 原文地址:https://blog.csdn.net/weixin_43263355/article/details/126761553