Vuex回顾及模拟实现

435 阅读3分钟

一、VueX回顾

1、vuex是什么?

  • Vuex是专门为Vue.js设计的状态管理库
  • Vuex采用集中式的方式存储需要共享的状态
  • Vuex的作用是进行状态管理,解决复杂组件通信,数据共享
  • Vuex集成到了devtools中,提供了time-travel时光旅行,历史回滚功能

2、Vuex核心概念

  • state:提供唯一的公共数据源,所有共享的数据都要统一放到StoreState 中进行存储。
  • mutation:用于变更 Store中 的数据。只能通过 mutation 变更 Store 数据,不可以直接操作 Store 中的数据。通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
  • action:用于处理异步任务。如果通过异步操作变更数据,必须通过 Action,而不能使用 Mutation,但是在 Action 中还是要通过触发 Mutation 的方式间接变更数据。
  • Getter:用于对 Store 中的数据进行加工处理形成新的数据。Getter 可以对 Store 中已有的数据加工处理之后形成新的数据,类似 Vue计算属性Store 中数据发生变化,Getter 的数据也会跟着变化。

3、总结使用

  • mutations中的函数第一个参数都是state,后面只能接收一个参数,如果要传递多个参数,可以使用对象来传递参数,使用时使用解构获取参数
  • actions中接收参数context代表new出来的new Vuex.Store实例
  • getters中接收参数state
  • state相当于vue中的data
  • mutations相当于vue中的methods
  • actions是异步的methods,
  • getters相当于vue中的computed属性
  • state,getters可以放到vuecomputed
  • mutations,actions放在vuemethods

4、Vuex严格模式

export default new Vuex.Store({  
  strict: process.env.NODE_ENV !== 'production',
  state: {
    count: 0,
    msg: 'Hello Vuex'
  },
  getters: {
    reverseMsg (state) {
      return state.msg.split('').reverse().join('')
    }
  },
  mutations: {
    increate (state, payload) {
      state.count += payload
    }
  },
  actions: {
    increateAsync (context, payload) {
      setTimeout(() => {
        context.commit('increate', payload)
      }, 2000)
    }
  },
  modules: {
    products,
    cart
  }
})

严格模式会深度检查状态树,查找不合规的状态改变,耗性能,不建议生产环境开启。

二、模拟Vuex

1、实现思路

  • 实现install方法
    • VuexVue的一个插件,所以和模拟VueRouter类似,先实现Vue插件约定的 install方法,Vue.use的时候会调用这个方法。
  • 实现Store
    • 实现构造函数,接收options
    • state的响应化处理
    • getter的实现
    • 在视图中修改状态可以直接调用$store.commit提交mutation
    • 在视图中执行异步操作可以调用$store.dispatch分发action

2、实现过程

  • install中需要做的事情
    • 需要把创建 Vue 实例的时候传入的 store 对象注入到 Vue 原型上的 $store, 在所有组件中可以直接通过 this.$store 来获取到vuex中的仓库, 从而可以在所有组件中共享状态.
    • install 中我们获取不到 Vue 实例, 所以这里通过混入 beforeCreate 来获取 Vue 实例从而拿到选项中的 store 对象
    • 注册插件的时候会混入beforeCreate, 当创建Vue的根实例的时候就会把store注入到所有Vue实例上
  • 完整代码
let _Vue = null
class Store {
  constructor (options) {
    // 解构options参数
    const {
      // 防止用户未传入 设置默认对象        
      state = {},
      getters = {},
      mutations = {},
      actions = {}
    } = options
    // 设置state的响应式
    this.state = _Vue.observable(state)
    this.getters = Object.create(null)
    /* 
      此处不直接 this.getters = getters,是因为下面的代码中要方法 getters 中的 key
      如果这么写的话,会导致 this.getters 和 getters 指向同一个对象
      当访问 getters 的 key 的时候,实际上就是访问 this.getters 的 key 会触发 key 属性的 getter
      会产生死递归
    */
    Object.keys(getters).forEach(key => {
      Object.defineProperty(this.getters, key, {
        // 返回指定getter方法,并传递state参数
        get: () => getters[key](state)
      })
    })
    // 初始化mutations
    this._mutations = mutations
    // 初始化actions
    this._actions = actions
  }

  commit (type, payload) {
    this._mutations[type](this.state, payload)
  }

  dispatch (type, payload) {
    this._actions[type](this, payload)
  }
}

function install (Vue) {
  _Vue = Vue
  _Vue.mixin({
    // 混入到beforeCreate阶段
    beforeCreate () {
      // 如果是组件实例 没有store选项就不需要挂载原型
      if (this.$options.store) {
        _Vue.prototype.$store = this.$options.store
      }
    }
  })
}

export default {
  Store,
  install
}