Vuex的基本原理

953 阅读5分钟

一、如何跟踪vuex的函数执行过程

1.安装开发环境安装

vscode,git,nodejs,vue-cli等开发工具的步骤本文就略过了。默认已安装好此依赖。执行Vue init webpack-simple [appname]根据提示构建出一个简单的vue工程,因为只是用来研究vuex的运行机制,尽量简化的工程可以减少不必要的干扰。惯例,npm install

安装依赖。安装好依赖后工程是这样子的。

2.引入vuex示例

修改App.vue代码(为了简单演示)

<template>

  <div id="app">

    <span>{{ counter }}</span>

    <button @click="increment">点击触发mutation</button>

     <button @click="incrementAsyc">点击触发action</button>

  </div>

</template>

<script>

export default {

  name: 'app',

  data () {

    return {

    }

  },

  computed: {

     counter() {

       return this.$store.state.count

     }

  },

  methods: {

    increment() {

       this.$store.commit('increment')

    },

    incrementAsyc() {

      this.$store.dispatch('incrementAsync')

   }

  },

}

</script>

修改main.js,引入vuex

import Vue from 'vue'

import App from './App.vue'

import vuex from 'vuex'

import storeOption from './store'

Vue.use(vuex)

const store = new vuex.Store(storeOption)

new Vue({

  el: '#app',

  store,

  render: h => h(App)

})

在此之前我们要执行npm install vuex --save,将vuex
的依赖包引入项目。至此一个vuex简单应用就构建好了,下面开始跟踪vuex
的调试跟踪。

执行命令
npm run dev
会启动项目。控制台会显示项目启动后本地的地址。用Chrome打开此地址。


按crtl+shift+I代开控制台,切换至sources标签。打开如图所示的文件,找到你感兴趣的文件,加上断点(点击行号的位置),开始调试,有一些代码位置可能已经运行过了,这是后你可能需要刷新浏览器,代码才会重新运行至该位置。


如果关心this.$store.commit导致发生了什么可以在此处加上断点,然后点击【点击触发
mutation】的按钮,代码就会停在此处。


控制台有调试控制按钮以及堆栈信息,局部scope等信息。


然后通过f9,f10,f11等快捷键单步调试或者跳出函数等调试功能即可跟踪整个vuex的运行状态。另外vuex的大部分的初始化工作是在执行Vue.use(vuex)和创建new vuex.Store时完成的,想要了解vuex的初始化过程需要跟踪这两行代码的运行情况。

二、vuex运行的基本原理

上面介绍了vuex的代码运行状态的跟踪方法,有了上面的基本“捕鱼技术”只要有时间,逐行跟踪vuex的代码调用就可以完全弄清楚vuex的运行机理。下面主要从源码角度简单介绍一下

vuex的基本原理。Vuex的git地址为:https://github.com/vuejs/vuex.git
或者git@github.com:vuejs/vuex.git,github

1. vuex的初始化

调用Vue.use安装vue插件时,其实是会调用插件提供出来的install方法。Install函数中主要执行这段逻辑(不考虑vue2以下版本)。


可以看出,是在vue上全局混入(不明白全局混入,请自行百度vue的mixin)了一个初始化生命周期的钩子函数,也就是在初始化会执行vuexInit函数。


如果组件自身的store存在,则$store属性指向自身的store传入的store,否则则去找父亲组件的$store,所以vuex在根组件注入store对象之后,所有组件引用的store对象都来源于根组件。所以只要根组件申明了store属性,其他的组件都可以使用$store.(从代码中看出,还可以配置vuex属性来设置vuex的配置,此处不深入探索)。

2. vuex.Store的构造函数

注入根组件的store对象是通过vuex.Store类构造出来的。其中构造函数中最核心的几段代码如下:

这个函数中构建了一个Vue对象


构造一个Vue对象,其中引用store的state对象,然后获取的state就是这个Vue对象中的?state。如果了解Vue的双向数据绑定的话,这里很简单的用构造vue对象的方式,利用vue的双向数据绑定,将state对象变成响应对象。

这也是vuex的最基本原理。

这里当数据再引用state的任何属性,那么当引用的值发生变更时都会得到更新,同时也会存在和vue的双向数据绑定一样的问题就是直接添加的属性将无法有响应行为。(需要增加新属性,需要通过Vue.set函数)但是vuex的规范并不推荐我们这么做。Vuex的使用规范需要我们不直接修改state的值,而是通过mutation和action来修改。(但是理论上直接修改也能看到一样的效果)

其实上面的是核心,本文到这里差不多vuex的基本运行原理已经揭示的差不多了。剩下的部分无非是一些观察者模式的应用以及vuex官方提供的更加方便使用的助手方法而已。

3. commit和dispatch函数调用

commit函数主要逻辑



而entry是通过registerMutation函数创建出来

 commit函数中核心调用,调用_withCommit函数,这个函数是一个装饰函数。

用来记录一下commiting状态,便于vuex调试,然后调用回调,而回调就是每一个
commit的entry函数。Dispatch的分析也是一样的。

三、总结

小结一下vue的基本原理:

1. vuex

是用一个在内存中常驻的对象来实现单一状态树

2. vuex

的数据的响应原理是使用了vue的双向数据绑定功能

3. vuex

为我们提供了一系列的数据操作的规范(不直接修改数据,异步更新与同步更新封装不同函数,数据模块思想)

因为是内存对象,所以vuex无法实现跨窗口数据共享,同时刷新后,vuex的状态也都会消失(sessionStorage在刷新后数据不会消失,可以使用sessionStorage实现刷新数据状态保存,同时可以使用localStorage实现跨窗口数据共享,不过这些需求都跟SPA的理念相违背了,如果产品确实有这样的奇葩需求,只能通过这样来实现了)。

四、最后再说一点

vuex是vue的状态管理插件,与Flux和Redux的功能及设计理念都差不多。

Vuex的主要作用是作为vue单页面程序的状态管理程序,用于大型程序的组件之间的数据通信尤为合适。但是如果不清楚自己的项目是否需要vuex,那最好不要用vuex。
Vue官网推荐了简单的状态管理模式,这种模式更适合较为简单的组件之间的数据通信,storejs模式,这样可以更好的发挥就近原则,毕竟vuex的配置是全局级别的,开发的时候毕竟有一点割裂感,(在开发一个独立业务功能的页面还需要跑到不相关的文件中设置数据,添加方法,“调用”也是一样麻烦)而storejs模式可以仅仅在自己的业务范围之内共享状态。
Element UI的table组件就是用了这种模式。storejs模式的参考文章。

cn.vuejs.org/v2/guide/st…