Vuex源码浏览笔记

笔记中的Vue与Vuex版本为1.0.21和0.6.2,须要浏览者有运用Vue,Vuex,ES6的履历。

原由

俗话说得好,没有平白无故的爱,也没有平白无故的恨,更不会平白无故的去浏览他人的源代码。
之所以会去浏览Vuex的源代码,是因为在刚最先打仗Vuex时,就在官方文档的Actions部份,看到这么一句:

// the simplest action
function increment (store) {
  store.dispatch('INCREMENT')
}

// a action with additional arguments
// with ES2015 argument destructuring
function incrementBy ({ dispatch }, amount) {
  dispatch('INCREMENT', amount)
}

上面的Action还好说,能看懂,然则下面运用ES6写法的Action是什么鬼呀喂(摔!)
虽然晓得有解构赋值,然则谁人{ dispatch }又是从哪儿冒出来的呀喂!明显我在挪用时,没有传这个参数呀!
之前因为赶项目进度,所以抱着能用就行的立场,也就没管那末多。现在有了余暇时候,必需好好研讨一下呀。
而研讨最好的体式格局,就是浏览Vuex的源代码。如许就能够弄清楚,谁人{ dispatch }究竟从哪儿冒出来的。

Vuex源代码简介

Vuex的源代码量挺少的,加起来也才600行不到,然则个中大批运用了ES6的语法,且部份功用(如Vuex初始化)运用到了Vue。所以读起来照样有些费力的。
全部Vuex的源代码,核心内容包含两部份。一部份是Store的组织函数,另一部份则是Vuex的初始化函数。
而适才题目的答案,就在第二部份。

题目场景复原

起首要引见的,就是Vuex在Vue项目中的初始化。这儿贴一段代码:
起首是Vuex中,我写的Actions源代码:

// global/Vuex/action.js
export const getMe = ({ dispatch }) => {
  /**
   * 异步操纵,猎取用户信息,并存入Vuex的state中
   */
  res.user.get_me()
  .then(data => {
    dispatch('GET_ME', data)
  })
  .catch(err => {
    console.log(err)
  })
}

这个则是顶层组件,挪用store的处所。因为Vuex的特性,store只须要在最顶层的组件声明一次。

<template>
  <div id="wrapper">
    <router-view></router-view>
  </div>
</template>

<script type="text/javascript">
  import store from './Vuex/store.js'

  export default {
    store
  }
</script>

接下来则是组件中,则是现实挪用Vuex的代码。

// index.vue
import { getMe } from './../global/Vuex/action'

export default {

  vuex: {
    actions: {
      getMe
    },
    getters: {
      // 从state中猎取信息
      user: state => state.user
    }
  },

  ready() {
    // 最先猎取用户信息
    this.getMe()
  }
}

在这儿,能够很明显的看出,我在运用this.getMe()时,是没有任何参数的。然则在getMe函数的定义中,是须要解构赋值出{dispatch}的。
就比方说这个:

function getX({ x }) {
  console.log(x)
}

getX({ x: 3, y: 5 })
// 3

你得传入响应的参数,才举行解构赋值。
同时,我注意到在Vuex的Actions挪用,须要在Vue的options的Vuex.actions中先声明,以后才运用。
那末,肯定是Vuex对这个Action动了四肢。(逃)
而动四肢的代码,就存在于Vuex源代码的override.js中。这个文件,是用于初始化Vuex的。

Vuex的初始化

override.js中,有个vuexInit的函数。看名字就晓得,这是拿来初始化Vuex的。
在代码开首,有这么一句:

const options = this.$options
const { store, vuex } = options
// 觉得解构赋值真的很棒,如许写能省许多时候。
// 下面的是老写法
// const store = options.store
// const vuex = options.vuex

在这儿,用因而在Vue中挪用,所以this指向Vue,而this.$options则是Vue的设置项。
也就是写Vue组件时的:
export default {……一些设置}
这里,就把Vue设置项的store和vuex抽离出来了。

征采store

接下来,则看到了Vuex源代码的精巧的地方:

// store injection
if (store) {
  this.$store = store
} else if (options.parent && options.parent.$store) {
  this.$store = options.parent.$store
}

解构赋值并非肯定胜利的,假如store在options中不存在,那末store就会是undefined。然则我们须要找store。
因而Vuex供应了向父级(Vue中的功用)寻觅store的功用。不难看出,这儿父级的$store假如不存在,那末实在他也会到本身的父级去寻觅。直到找到为止。
就想一条锁链一样,一层一层的连到最顶部store。所以在没有找到时,Vuex会给你报个毛病。

// 声清楚明了Vuex但没有找到store时的状态
if (vuex) {
  if (!this.$store) {
    console.warn(
      '[vuex] store not injected. make sure to ' +
      'provide the store option in your root component.'
    )
  }

对Vuex声明的内容,举行革新

接下来,则是对Vuex声明的内容,举行革新。
起首的是猎取Vuex对象的内容:

let { state, getters, actions } = vuex

同时,在这儿还看到了对过期API的处置惩罚。觉得算是意料之外的欣喜。

// handle deprecated state option
// 假如运用state而不是getters来猎取Store的数据,则会提醒你state已过期的,你须要运用新的api。
// 然则,这儿也做了兼容,确保晋级时效劳不会挂掉。
if (state && !getters) {
  console.warn(
    '[vuex] vuex.state option will been deprecated in 1.0. ' +
    'Use vuex.getters instead.'
  )
  getters = state
}

接下来,则是对getters和actions的处置惩罚:

// getters
if (getters) {
  options.computed = options.computed || {}
  for (let key in getters) {
    defineVuexGetter(this, key, getters[key])
  }
}
// actions
if (actions) {
  options.methods = options.methods || {}
  for (let key in actions) {
    options.methods[key] = makeBoundAction(this.$store, actions[key], key)
  }
}

能够看出,在这儿对getters和actions都举行了分外处置惩罚。
在这儿,我们报告actions的分外处置惩罚,至于getters,触及了过量的Vue,而我不是很熟悉。等我多研讨后,再写吧。

Actions的革新

对全部Actions的革新,起首是Vuex的检测:

// actions
if (actions) {
  // options.methods是Vue的methods选项
  options.methods = options.methods || {}
  for (let key in actions) {
    options.methods[key] = makeBoundAction(this.$store, actions[key], key)
  }
}

在这儿,我们一点一点的理会。能够看出,一切的actions,都会被makeBoundAction函数处置惩罚,并到场Vue的methods选项中。
那末看来,makeBoundAction函数就是我要找的答案了。
接下来贴出makeBoundAction函数的源代码:

/**
 * Make a bound-to-store version of a raw action function.
 *
 * @param {Store} store
 * @param {Function} action
 * @param {String} key
 */

function makeBoundAction(store, action, key) {
  if (typeof action !== 'function') {
    console.warn(`[vuex] Action bound to key 'vuex.actions.${key}' is not a function.`)
  }
  return function vuexBoundAction(...args) {
    return action.call(this, store, ...args)
  }
}

事变到这儿,实在已豁然晴明了。
我在Vuex中传入的actions,现实会被处置惩罚为vuexBoundAction,并到场options.methods中。
在挪用这个函数时,现实上的action会运用call,来转变this指向并传入store作为第一个参数。而store是有dispatch这个函数的。
那末,在我传入{dispatch}时,自然而然就会解构赋值。
如许的话,也形成了闭包,确保action能访问到store。

结语

本日应当算是处理了心中的一个大迷惑,照样那句话:

没有平白无故的爱,也没有平白无故的恨,更没有平白无故冒出来的代码。

全部源代码读下来一遍,虽然有些部份不太明白,然则对ES6和一些代码的运用的明白又加深了一步。比方这回就稳固了我关于ES6解构赋值的学问。而且还收成了许多别的东西。总而言之,收成颇丰~
末了的,依然是那句话:前端路漫漫,且行且歌。

末了附上本人博客地址和原文链接,愿望能与列位多多交换。

Lxxyx的前端乐土
原文链接:Vuex源码浏览笔记

    原文作者:Lxxyx
    原文地址: https://segmentfault.com/a/1190000004954409
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞