vue2手写vuex

4.29 手写 vuex

let Vue 
class Store{
    constructor(options){
        // step1 step1注册$store后让页面能正常显示state
        // this.state = options.state


        // step2实现mutations actions commit dispatch 
        // step2-01 初步实现mutations actions commit dispatch 
        this._mutations = options.mutations
        this._actions = options.actions 

        // step2-02 锁死commit和dispatch的this指向
        this.commit = this.commit.bind(this)
        this.dispatch = this.dispatch.bind(this)


        // step2-03 让state响应 触发render组件重新渲染
        // 如何造响应式数据?
        // 方式1:借鸡生蛋 - new Vue({data: {XXX: '/'}})
        // 方式2:Vue.util.defineReactive(obj, 'XXX', '/')
        // step2-03 让state变成响应式 同时state不可以随意改变
        this._vm = new Vue({
            data:{
                // Vue约定:以 _ 或 $ 开头的属性 不会 被 Vue 实例代理
                $$state : options.state
            }
        })
    }

    // step2-03 让state变成响应式 同时state不可以随意改变
    get state(){
        return this._vm._data.$$state
    }

    set state(v){
        console.error('请使用replaceState重置状态');
    }

    // step2-01 初步实现mutations actions commit dispatch
    commit(type,payload){
        console.log('in commit:',this.state)
        const mutation = this._mutations[type]
        if(!mutation){
            console.error('mutation不存在')
            return
        }
        mutation(this.state,payload)
    }
    dispatch(type,payload){
        const action = this._actions[type]
        if(!action){
            console.error('action不存在')
            return
        }
        // 为什么第一个是this,也就是Store,因为action中需要commit,可以在Store拿到
        action(this,payload)
        // 报错  Cannot read property 'state' of undefined
        // 由于dispatch通常是异步的,所以会异步commit。而commit依赖this.state,但是异步容易丢失上下文,所以我们在constructor中锁死commit和dispatch的this指向 ===》 step2-02
    }
    // OK step2已经完成 但是我们可以发现一个问题 页面上state不会变化,我们需要让Store.state变成响应式数据,触发Vue的render组件渲染 ===》step2-03
}

// 入口:install 
function install(_Vue){
    // 保存Vue
    Vue = _Vue
    // step1注册$store
    Vue.mixin({
        beforeCreate(){ 
            /**
             * this.$options用来访问main.js中
               new Vue({
                    render: h => h(App),
                    store,
                })中的options 这里我们是要拿到store
             */
            if(this.$options.store)Vue.prototype.$store = this.$options.store
        }
    })
    
}
export default {Store,install}

  

posted @ 2021-04-30 11:43  心中有一海  阅读(82)  评论(0编辑  收藏  举报