vuex和普通的event-bus有什么不同


vuex和普通的event-bus有什么不同

我們都知道,vuex 的底層實現原理其實就是 event-bus,那么它和普通的 event-bus 有什么不同呢?我們通過簡單的源碼一步步實現來搞懂這個問題。

參考資料:手寫Vuex核心原理

event-bus

首先一個普通的 event-bus 是這樣的:

// main.js
Vue.prototype.$bus = new Vue();

// 組件中
this.$bus.$on('console', (text) => {
    console.log(text);
});

// 組件中
this.$bus.$emit('console', 'hello world');

它是通過 Vue 的$on$emit api 來傳遞消息的。

vuex 的響應式數據

而 vuex 的數據是響應式的,那么我們首先實現這種響應式數據:

class store {
    constructor(options) {
        this.vm = new Vue({
            data: {
                state: options.state
            },
        });
    }

    get state() {
        return this.vm.state;
    }
}

注意,上面的data不是一個函數,因為這里我們只會實例化一次。然后我們通過添加一個 state 的 getter 方法來暴露內部的 event-bus 的 state 屬性。

那怎么實現響應式的呢?因為在實例化 vm 的時候,Vue 會自己使用 defineReactive 把 data 變為響應式數據,從而會收集有關它的依賴,然后在自己變動的時候,通知依賴更新。

加上 getters

vuex支持加上 getters,怎么加呢?直接初始化一個 getters 屬性即可:

class store {
    constructor(options) {
        this.vm = new Vue({
            data: {
                state: options.state
            },
        });

        const getters = options.getter || {};
        this.getters = {};
        Object.keys(getters).forEach((key) => {
            Object.defineProperty(this.getters, key, () => {
                get: () => getters[key](this.state)
            })
        });
    }

    get state() {
        return this.vm.state;
    }
}

原理就是添加一個 getters 屬性,然后遍歷 getters 並綁定到它的各個屬性的 getter 上面去即可。

加上 mutations

類似的,我們可以添加一個 mutations 屬性來保存 mutations,然后實現一個 commit 方法,在調用 commit 方法的時候去 mutations 里面找,然后調用相應函數即可:

class store {
    constructor(options) {
        this.vm = new Vue({
            data: {
                state: options.state
            },
        });

        const getters = options.getters || {};
        this.getters = {};
        Object.keys(getters).forEach((key) => {
            Object.defineProperty(this.getters, key, () => {
                get: () => getters[key](this.state)
            })
        });

        const mutations = options.mutations || {};
        this.mutations = {};
        Object.keys(getters).forEach((key) => {
            this.mutations[key] = (args) => mutations[key](state, args);
        });
    }

    get state() {
        return this.vm.state;
    }

    commit(name, args) {
        this.mutations[name](args);
    }
}

加上 actions

類似的,我們可以添加一個 actions 屬性來保存 actions,然后實現一個 dispatch 方法,在調用 dispatch 方法的時候去 actions 里面找,然后調用相應函數即可。不過稍有不同的是,actions 里面的方法和 mutations 里面的方法的第一個參數不同,它要傳整個 store 進去,因為不僅要獲得 state,還需要在里面調用 commit 方法:

class store {
    constructor(options) {
        this.vm = new Vue({
            data: {
                state: options.state
            },
        });

        const getters = options.getters || {};
        this.getters = {};
        Object.keys(getters).forEach((key) => {
            Object.defineProperty(this.getters, key, () => {
                get: () => getters[key](this.state)
            })
        });

        const mutations = options.mutations || {};
        this.mutations = {};
        Object.keys(mutations).forEach((key) => {
            this.mutations[key] = (args) => mutations[key](state, args);
        });

        const actions = options.actions || {};
        this.actions = {};
        Object.keys(actions).forEach((key) => {
            this.actions[key] = (args) => actions[key](this, args);
        });
    }

    get state() {
        return this.vm.state;
    }

    commit(name, args) {
        this.mutations[name](args);
    }

    dispatch(name, args) {
        this.actions[name](args);
    }
}

其它

后面install流程就和其它插件的install流程差不多一樣了,唯一需要注意的是插入到 beforeCreate 鈎子里面的代碼,它是通過獲取父級的 store 來獲取全局 store 的

可以看到,vuex 和傳統的 event-bus 的不同點除了 vuex 實現了更加友好的響應式狀態之外,還禁止了 vuex 里面數據的直接修改,大大增強了信任度(有點像promise的status),通過增加 mutations 和 actions 這種“中間層”,它能更好的控制中間的變化,比如實現時間旅行、狀態回退和狀態保存的功能。

另外,需要說明的是,mutation 和 action 的不同點不僅在於 mutation 里面只能寫同步代碼,action 里面只能寫異步代碼,還在於 mutation 里面的方法的第一個參數state(因為只需要修改 state 就可以了),而 action 里面的方法的第一個參數是store(因為還需要調用 commit 方法)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM