1.vuex的简介

Vuex 集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以可预测的方式发生变化。
简而言之就是集中式的管理和可预测的变更,且所有的组件状态集中被一个叫做store的类来管理。

2.实现vuex的需求分析

实现插件

  1. 实现Store类
    1. 维持一个响应式状态state
    2. 实现commit()
    3. 实现dispatch()
    4. getters
  2. 挂载$store

3.vuex源码实现

3.1 在src/main.js添加实例
import store from './kstore'
new Vue({
  store,
}).$mount("#app");
3.2 在HelloWorld.vue添加以下测试代码
<div class="hello">
  <h1>{{ msg }}</h1>
  <p @click="$store.commit('add')">counter: {{$store.state.counter}}</p>
  <p @click="$store.dispatch('add')">async counter: {{$store.state.counter}}</p>
  <p>doubleCount:{{$store.getters.doubleCounter}}</p>
</div>
4.3 在src/kstore/index.js使用自定义的kvuex插件
import Vue from 'vue'
import Vuex from './kvuex-ckk'
Vue.use(Vuex)
4.4 在src/kstore/kvuex.js自定义kvuex插件
// 1.插件:挂载$store
// 2.实现Store

let Vue;

class Store {
  constructor(options) {
    this._mutations = options.mutations
    this._actions = options.actions
    this._wrappedGetters = options.getters

    // 定义computed选项
    const computed ={}
    // 暴露一个getters用于用户store.getters
    this.getters = {}
    const store = this
    Object.keys(this._wrappedGetters).forEach(key =>{
      //获取用户定义的getter
      const fn = store._wrappedGetters[key]

      // 转换为computed可以使用的无参数形式
      computed[key] = function(){
        return fn(store.state)
      }
      // 为getters定义只读形式
      Object.defineProperty(store.getters,key, {
        get:()=> store._vm[key]
      })
    })

    // data响应式处理
    // this.$store.state.xx
    // 1、将state设为响应式
    // 方法一:
    // Vue.util.defineReactive(this,'state',options.state)
    // 方法二:
      // 不可以直接接触当前的Vue的实例this.state = new Vue,因为这样就违背了可预测的原则,
      // 因因此需要约束一下用户,不要直接接触当前的Vue实例
    // this.state = new Vue({
    //   data(){
    //     return options.state
    //   }
    // })
    // 起_vm的原因是不希望通过_vm.store来访问,可以通过get、set两个存取器方法
    this._vm = new Vue({
      data: {
        // 加上两$,不让Vue做代理,这样$$state就不会挂载到暴露的那个Vue实例上去了
        $$state: options.state
      },
      computed
    })

    // 当真正执行的时候,this会混乱因为在调用dispatch时要先调用一下mutations,
    // 所以就导致this的混乱,所以应该提前将commit和dispatch绑定一下当前实例this
    this.commit = this.commit.bind(this)
    this.dispatch = this.dispatch.bind(this)
  }

  get state() {
    // _data和$data是一样的,_data和是为了内部使用,$data是为了暴露给外部,可以打印输出_vm去查看一下
    return this._vm._data.$$state
  }

  set state(v) {
    // 禁止修改state
    console.error('please use replaceState to reset state');
  }
  // type:mutation的名称,
  // payload:可能用户传过来的参数列表
  commit(type, payload) {
    const mutations = this._mutations[type]
    // console.log(mutations);
    // console.log(this.state);
    // console.log(payload);
    if (!mutations) {
      console.error('unkown mutation type');
      return
    }
    // 这里的mutations的就是一个方法格式如下:
    // ƒ add(state) {
    //   // state从哪来?
    //   state.counter++;
    // }
    // 当mutations被执行的时候,将响应式的this.state传递进去,
    // 当响应式的对象被改变,导致对他有依赖的组件会被重新render
    mutations(this.state, payload)
  }

  // 当真正执行的时候,this会混乱因为在调用dispatch时要先调用一下mutations,
  // 所以就导致this的混乱,所以应该提前将commit和dispatch绑定一下当前实例this
  dispatch(type, payload) {
    const action = this._actions[type]
    if (!action) {
      console.error('unkown action type');
      return
    }
    // action(ctx,payload)
    // ctx俗称上下文,包括{cmmit,dispatch,state,rootState},所以这里就传入this即可
    action(this, payload)
  }

}

// Vue.use
// install.apply(this, [this,...])
function install(_Vue) {
  Vue = _Vue
  // 全局混入注册$store
  Vue.mixin({
    beforeCreate() {
      // 判断是否是根实例
      if (this.$options.store) {
        Vue.prototype.$store = this.$options.store
      }
    }
  })
}
// Store代表Vuex
export default { Store, install };

集中式的管理和可预测的变更

所有的组件状态集中被一个叫做store的类来管理

改变状态的唯一方式就是commit,

dispatch提交action之前也要commit一下

但是在commit之前可以插入一些插件做一下commit之前的事情,比如状态的持久化,
日志记录方便用户之后回溯整个过程只要在store中实现一个响应式的数据对象就可以了。

单项数据流、集中数据管理、可预测的状态更新

源码的角度解析router-view
vue-router源码
https://github.com/vuejs/vue-router/blob/dev/src/components/view.js

评 论