vuex 源码解析(四) mutation 详解

mutation是更改Vuex的store中的状态的唯一方法,mutation类似于事件注册,每个mutation都可以带两个参数,如下:

  state     ;当前命名空间对应的state

  payload     ;传入的参数,一般是一个对象

创建Vuex.Store()仓库实例时可以通过mutations创建每个mutation

我们不能直接调用一个mutation,而是通过 store.commit来调用,commit可以带两个参数,如下:

  type     ;对应的mutation名

  payload    ;传入的参数

commit还有一种写法,就是传入一个对象即可,该对象可以带一个type参数,type指定为mutation的名称,整个对象会作为参数传递给mutation。注意:mutation里包含的是同步操作

例如:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <script src="https://unpkg.com/[email protected]/dist/vuex.js"></script>
</head>
<body>

    <div id="app">
        <p>{{no}}</p>
        <button @click="test1">测试1</button>
        <button @click="test2">测试2</button>
    </div>
    <script>
        const store = new Vuex.Store({
            state:{no:100},
            mutations:{
                increment(state,payload){state.no+=payload.no;}
            }
        })
        var app = new Vue({
            el:"#app",
            store:store,
            computed:{
                no(){return this.$store.state.no }
            },
            methods:{
                test1(){
                    this.$store.commit(‘increment‘,{no:100})            //一般调用mutation的方法
                },
                test2(){
                    this.$store.commit({type:‘increment‘,no:100})       //mutation的另一种写法
                },
            }
        })
    </script>

</body>
</html>

源码分析



在创建Vuex.Store()初始化时会执行installModule()安装根模块,和mutation相关的如下:

  function installModule (store, rootState, path, module, hot) {      //安装模块
    /*略*/

    module.forEachMutation(function (mutation, key) {                   //遍历module模块的mutations对象,如果找到了,则执行这个匿名函数 参数1:每个mutation值 key:对应的键名
      var namespacedType = namespace + key;                                 //拼凑namespacedType
      registerMutation(store, namespacedType, mutation, local);             //调用registerMutation注册mutation
    });
    /*略*/
  }

registerMutation用于注册mutation的,如下:

  function registerMutation (store, type, handler, local) {             //注册Mutations
    var entry = store._mutations[type] || (store._mutations[type] = []);  //如果store对象的_mutations对应的为空,则初始化为数组
    entry.push(function wrappedMutationHandler (payload) {                //则将一个匿名函数push到entry里面
      handler.call(store, local.state, payload);                            //上下文是store,参数1为local.state,参数2为payload
    });
  }

writer by:大沙漠 QQ:22969969

也就是说注册完后对应的mutation会存储在store._mutations里,这是一个对象,每个键是一个mutation,而值就是对应的mutation,是个数组,例如例子里执行到这里时对应的_mutation如下:

等到我们调用this.$store.commit(‘increment‘,{no:100})去触发一个mutation时首先会触发Store函数内重定义的commit,它会以当前Store函数对象为上下文继续执行Store原型上的commit函数,如下:

  Store.prototype.commit = function commit (_type, _payload, _options) {      //对mutation的处理
      var this$1 = this;

    // check object-style commit
    var ref = unifyObjectStyle(_type, _payload, _options);                      //规范一下参数,返回一个对象,例如:{options: undefined,payload: {no: 100},type: "increment"}
      var type = ref.type;                                                      //mutagion类型:比如:increment
      var payload = ref.payload;                                                //传递过来的参数
      var options = ref.options;                                                //选项

    var mutation = { type: type, payload: payload };
    var entry = this._mutations[type];                                          //直接从this._mutations里获取type类型的mutaion,是个函数数组
    if (!entry) {                                                               //如果该mutaion不存在,则报错
      {
        console.error(("[vuex] unknown mutation type: " + type));
      }
      return
    }
    this._withCommit(function () {                                              //在this._withCommit()环境下执行该函数
      entry.forEach(function commitIterator (handler) {                           //遍历entry,依次执行每个handler函数,参数为payload
        handler(payload);
      });
    });
    this._subscribers.forEach(function (sub) { return sub(mutation, this$1.state); });

    if (
      options && options.silent
    ) {
      console.warn(
        "[vuex] mutation type: " + type + ". Silent option has been removed. " +
        ‘Use the filter functionality in the vue-devtools‘
      );
    }
  };

unifyObjectStyle是一个工具函数,它会修正参数,并返回一个对象,如下:

  function unifyObjectStyle (type, payload, options) {        //统一object的类型
    if (isObject(type) && type.type) {                          //如果type是个类型且含有type属性,比如这样的格式:this.$store.commit({type:‘increment‘,no:1000})
      options = payload;
      payload = type;
      type = type.type;
    }

    {
      assert(typeof type === ‘string‘, ("expects string as the type, but found " + (typeof type) + "."));
    }

    return { type: type, payload: payload, options: options }   //最后返回该对象
  }

我们在例子里可以用两种方式来调用mutation也是这个unifyObjectStyle函数的作用

_withCommit是一个工具函数,如下:

Store.prototype._withCommit = function _withCommit(fn) {                //执行fn函数 执行时设置this._committing为true,执行完后设置为false
    var committing = this._committing;                    //保存this._committing到局部变量committing里
    this._committing = true;                        //设置this._committing为true
    fn();                                 //执行fn函数
    this._committing = committing;                      //恢复this._committing
};

它在执行传入的函数时会设置Store._committing为true,这样就相当于设置了一个标记,表示当前是通过mutation来修改state的,还记得上一节说的strict严格模式吗,它就是通过这里的_committing来判断是否合法的。

原文地址:https://www.cnblogs.com/greatdesert/p/11424193.html

时间: 2024-10-06 23:39:56

vuex 源码解析(四) mutation 详解的相关文章

Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?

Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? ??如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一样,本篇文章最最核心的要点就是 SqlSession实现数据库操作的源码解析.但按照惯例,我这边依然列出如下的问题: 1. SqlSession 是如何被创建的? 每次的数据库操作都会创建一个新的SqlSession么?(也许有很多同学会说SqlSession是通过 SqlSessionFactor

Spring 源码解析之ViewResolver源码解析(四)

Spring 源码解析之ViewResolver源码解析(四) 1 ViewResolver类功能解析 1.1 ViewResolver Interface to be implemented by objects that can resolve views by name. View state doesn't change during the running of the application, so implementations are free to cache views. I

Spark Streaming源码解读之Job详解

一:Spark Streaming Job生成深度思考 1. 做大数据例如Hadoop,Spark等,如果不是流处理的话,一般会有定时任务.例如10分钟触发一次,1个小时触发一次,这就是做流处理的感觉,一切不是流处理,或者与流处理无关的数据都将是没有价值的数据,以前做批处理的时候其实也是隐形的在做流处理. 2. JobGenerator构造的时候有一个核心的参数是jobScheduler, jobScheduler是整个作业的生成和提交给集群的核心,JobGenerator会基于DStream生

iOS即时通讯之CocoaAsyncSocket源码解析四

原文 前言: 本文为CocoaAsyncSocket源码系列中第二篇:Read篇,将重点涉及该框架是如何利用缓冲区对数据进行读取.以及各种情况下的数据包处理,其中还包括普通的.和基于TLS的不同读取操作等等.注:由于该框架源码篇幅过大,且有大部分相对抽象的数据操作逻辑,尽管楼主竭力想要简单的去陈述相关内容,但是阅读起来仍会有一定的难度.如果不是诚心想学习IM相关知识,在这里就可以离场了... 注:文中涉及代码比较多,建议大家结合源码一起阅读比较容易能加深理解.这里有楼主标注好注释的源码,有需要的

spring 源码解读与设计详解:2 BeanFactory

在spring的官网中我们看到,spring的产品已经发展的非常壮大,然而很多产品对于很多公司来讲用的非常少,甚至用不到.因此本系列的源码解读也不会涉及全部的spring的产品.而是只对spring的核心功能IoC和AOP进行解释. 所谓源码解读,解读的是什么?实际上源码解读读的更多的是源码的注释,因为一个类的作用.一个接口或者一个方法的作用,我们往往是要根据注释才知道,这也是为什么在代码规范中,注释是一个非常重要的模块的原因. 参考: Spring源码分析--BeanFactory体系之接口详

AFNetworking2.0源码解析&lt;四&gt;

结构 AFURLResponseSerialization负责解析网络返回数据,检查数据是否合法,把NSData数据转成相应的对象,内置的转换器有json,xml,plist,image,用户可以很方便地继承基类AFHTTPResponseSerializer去解析更多的数据格式,AFNetworking这一套响应解析机制结构很简单,主要就是两个方法: 1.-validateResponse:data:error: 基类AFHTTPResponseSerializer的这个方法检测返回的HTTP

CentOS7最小化源码安装LAMP-步骤详解

系统:CentOS 7.3.1611(最小化安装) 软件:httpd-2.4.27 mysql-5.7.18 php-5.6.3 一.配置系统环境 1.1. 查看系统版本 # cat /etc/centos-release CentOS Linux release 7.3.1611 (Core) 1.2. 查看防火墙状态,关闭防火墙及其开机启动 # systemctl status firewalld # systemctl stop firewalld # systemctl disable

CentOS6系统源码安装LNMP环境详解

一.安装nginx 以下命令均在root权限下执行,普通用户可通过su命令切换1.安装依赖 yum install gcc-c++ yum install pcre pcre-devel yum install openssl openssl-devel 2.下载源码 wget http://nginx.org/download/nginx-1.8.1.tar.gztar -zxvf nginx-1.8.1.tar.gzcd nginx-1.8.1 3.创建nginx用户 useradd -M 

linux下源码编译安装mysql详解

1.redhat5环境下,首先安装编译环境 yum groupinstall -y  "Development Libraries"   "Development Tools" 2.由于源码编译mysql需要cmake命令,所以先要编译安装cmake包 首先下载cmake包,这里下载使用cmake-2.8.8.tar.gz tar xf cmake-2.8.8.tar.gz cd cmake-2.8.8 ./configure make && mak