手写简易vuex

273 阅读1分钟

微信公众号:  [大前端驿站]
关注大前端驿站。问题或建议,欢迎公众号留言。 这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

整合vuex

Vue cli创建的vue项目中安装:vue add vuex

核心概念:

  • state 状态、数据
  • getters 派生状态,类似于计算属性
  • mutations 更改状态的函数
  • actions 异步操作
export default new Vuex.Store({
  state: {
    counter: 0
  },
  mutations: {
    add(state) {
      state.counter++
    }
  },
  getters: {
    doubleCounter(state) {
      return state.counter * 2
    }
  },
  actions: {
    add({commit}) {
      setTimeout(() => {
        commit('add')
      }, 1000)
    }
  }
})

手写简易vuex

创建my-vuex.js:Store声明、install实现

let Vue

class Store {
  constructor(options = {}){
    this._vm = new Vue({
      data: {
        state: options.state
      }
    })
  }

  get state() {
    return this._vm._data.state
  }

  set state(v) {
    console.error('不能直接给state赋值!') // 这里通过拦截set属性防止直接赋值
  }
}

function install(_Vue){
  Vue = _Vue

  Vue.mixin({
    beforeCreate() {
      if(this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}

export default { Store, install }

处理getters: getters是store.vm的 computed

class Store {
 constructor(options = {}) {
    // 保存用户配置的getters选项
    wrapGetter(this, options.getters || {})
    resetStoreVM(this, options.state || {})
 }
}

function wrapGetter(store, moduleGetter) {
  Object.keys(moduleGetter).forEach(getterKey => {
    const rawGetter = moduleGetter[getterKey]
    // 将options中的getter赋值到_wrappedGetters
    // 因为computed的赋值就是return一个函数
    store._wrappedGetters = {}
    store._wrappedGetters[getterKey] = function wrappedGetter(store) {
      return rawGetter(
        store.state,
        store.getters
      )
    }
  })
}

function resetStoreVM(store, state) {
  store.getters = {}
  // 获取拼接的_wrappedGetters
  const wrappedGetters = store._wrappedGetters
  // 开始拼接computed
  const computed = {}
  Object.keys(wrappedGetters).forEach(key => {
    const fn = wrappedGetters[key]
    computed[key] = () => fn(store)
    Object.defineProperty(store.getters, key, {
      get: () => store._vm[key]
    })
  })
  store._vm = new Vue({
    data: {
      state
    },
    computed
  })
}

实现 commit: 根据用户传入 type 获取并执行对应 mutation

class Store {
  constructor(options = {}) {
    // 保存⽤户配置的mutations选项
    this._mutations = options.mutations || {}

    // 绑定commit上下文否则action中调用commit时可能会出问题!
    // 同时也把action绑定,因为action可以互调
    const store = this
    const {commit, action} = store
    this.commit = function boundCommit(type, payload) {
      commit.call(store, type, payload)
    }
  }
  // 实现commit: 根据用户传入type获取并执行对应mutation
  commit(type, payload) {
    // 获取type对应的mutation
    const entry = this._mutations[type]

    if(!entry) {
      console.error(`unknown mutation type: ${type}`)
      return
    }
    // 指定上下文为Store 传递state给mutation
    entry(this.state, payload)
  }
}

实现 actions:根据⽤户传⼊ type 获取并执⾏对应 action

class Store {
  constructor(options = {}) {
    // 保存⽤户编写的actions选项
    this._actions = options.actions || {}
    // 绑定commit上下⽂否则action中调⽤commit时可能出问题!!
    // 同时也把action绑了,因为action可以互调
    const store = this
    const {commit, action} = store
    this.commit = function boundCommit(type, payload) {
      commit.call(store, type, payload)
    }
    this.action = function boundAction(type, payload) {
      return action.call(store, type, payload)
    }
  }
  dispatch(type, payload) {
    const entry = this._actions[type]

    if(!entry) {
      console.error(`unknown action type: ${type}`)
      return
    }
    // 指定上下文为Store 传递state给mutation
    entry(this, payload)
  }

更改 store/index.js 中的 vuex 引用

// import Vuex from 'vuex'
import Vuex from '../myVuex/my-vuex.js'

启动项目看效果

vuex.gif




~~感谢观看

关注下方【大前端驿站】
让我们一起学,一起进步

【分享、点赞、在看】三连吧,让更多的人加入我们~~****