Vuex原理

210 阅读3分钟

Vuex 是什么?

首先我们可以看看vuex官方文档关于vuex的概念:
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state) 。Vuex 和单纯的全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

个人理解: vuex就是一个公共的资源共享库,可以供各个组件使用,方便组件之间的通信

Vuex原理理解

  1. Vuex本质上是一个对象
  2. Vuex对象有两个方法,一个是install方法,一个是Store类
  3. Store类里面有commit,dispatch这些方法

要怎么根据核心原理来实现vuex呢

首先看看vuex是怎么被使用的
store/index.js

import Vue from 'vue'
// import Vuex from 'vuex'
import Vuex from './myVuex'


Vue.use(Vuex)

export default new Vuex.Store({ 
  state: {
    num: 1
  },
  mutations: { // mutations里面的方法天生就具备参数,且参数为state, 这里面的方法可以改动state
    incre(state, arg) {
      state.num += arg
    }
  },
  actions: {  //Action 提交的是 mutation,而不是直接变更状态。Action 可以包含任意异步操作。
    asyncIncre({commit}, arg) { // actions里面的函数天生就具备一个参数,为一个对象{commit} (vuex的上下文)
      setTimeout(() => {
        commit('incre', arg)
      }, 1000)
    }
  },
  modules: {
  },
  getters: { // 派生出一些状态, 相当于组件中的 computed
    getNum (state) { //getters里面的方法天生就具备参数,且参数为state, 这里面的方法可以改动state
      return state.num*10
    }
  }
})

根据理解的vuex核心原理来实现一个vuex
store/myVue.js

// vuex 是一个对象,里面有个方法,一个是install,一个是Strore。首先定义store对象这里面挂载两个方法,install和Store
import Vue from 'vue' // 引入vue

class store {
    constructer(options) {
        // state 的实现
        this.vm = new Vue({  // 利用vue的data数据源,让state变成响应式
            data: {
            state: options.state || {}
            }
        }),
        
        // mutations 的实现
        let mutations = options.mutations || {}
        this.mutations = {}
        Object.keys(mutations).forEach(mutationName => { // 得到mutations对象里面的keys
            this.mutations[mutationName] = (arg) => { //  
                mutations[mutationName](this.state, arg) // 调用
            }
        }),
        
        // actions 的实现
        let actions = options.actions
        this.actions = {}
        Object.keys(actions).forEach(actionName => {
            this.actions[actionName] = (arg) => {
                actions[actionName](this, arg) // this是整个vue实例
            }
        })
        
        // getters的实现
        let getters = options.getters || {}
        this.getters = {}
        Object.keys(getters).forEach(getterName => {
            Object.defineProperty(this.getters, getterName, { // 数据拦截
                get: () => {  // 得到这个变量,可以用它的变量名显示
                    return getters[getterName](this.state)
                }
            })
        })
        }
        
        
     // 用来调用actions里面的方法
    dispatch(method, arg) {
        this.actions[method](arg)
    }
    // 用来调用mutations里面的方法
    commit = (method, arg) => {  // 注意作用域问题 this
        console.log(this);
        this.mutations[method](arg)
    }
    
    get state() {  // 函数前面加get,当我们要取函数内部的返回值时,只需要写函数名state就可以
        return this.vm.state
    }
    }


//因为vuex会被vue.use(vuex)
// 又因为被use的需规则要:
 // 1. Vue.use()接受一个参数,可以是对象,也可以是函数,如果是对象,该对象内必须具备install方法
// 2. use会将vue实例作为参数传递给install函数,且调用install函数
// 3. install方法被同一个插件多次调用时,插件也只会安装一次
// 所以vuex需要具备一个install方法,而且插件安装在new Vue 之前
    let install = function(Vue) {
    Vue.mixin({
        beforeCreate() { // vue初始化好
        // 如何把vuex实例$store分发给所有的组件使用
            if (this.$options && this.$options.store) { // this.$options用来获取页面根组件
                this.$store = this.$options.store // 往vue身上挂载了$store
            } else { // 子组件
                this.$store = this.$parent && this.$parent.$store 
            }
        },
    })
}


let Vuex = {
    Store,
    install
}

export default Vuex // 抛出

可以对实现的vuex进行测试
app.vue

<template>
  <div id="app">
    {{this.$store.state.num}}
    <p>{{this.$store.getters.getNum}}</p>
    <button @click="add">add</button>
    <button @click="asyncadd">add2</button>
  </div>
</template>

<script>
export default {
  methods: {
    add() {
      this.$store.commit('incre', 1)
    },
    asyncadd() {
      this.$store.dispatch('asyncIncre', 2)
    }
  },
}
</script>

总结

以上便是我对vuex的理解,如有不对指出希望大家能够指正,谢谢大家