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/vue@2.5.16/dist/vue.js"></script>
- <script src="https://unpkg.com/vuex@3.1.0/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来判断是否合法的。
vuex 源码解析(四) mutation 详解的更多相关文章
- 【源码解析】BlockManager详解
1 Block管理模块的组件和功能 BlockManager:BlockManager源码解析 Driver和Executor都会创建 Block的put.get和remove等操作的实际执行者 Bl ...
- vuex 源码分析(六) 辅助函数 详解
对于state.getter.mutation.action来说,如果每次使用的时候都用this.$store.state.this.$store.getter等引用,会比较麻烦,代码也重复和冗余,我 ...
- vuex 源码分析(五) action 详解
action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...
- 我的书籍《深入解析Java编译器:源码剖析与实例详解》就要出版了
一个十足的技术迷,2013年毕业,做过ERP.游戏.计算广告,在大公司呆过,但终究不满足仅对技术的应用,在2018年末离开了公司,全职写了一本书<深入解析Java编译器:源码剖析与实例详解> ...
- Mybatis源码解析(四) —— SqlSession是如何实现数据库操作的?
Mybatis源码解析(四) -- SqlSession是如何实现数据库操作的? 如果拿一次数据库请求操作做比喻,那么前面3篇文章就是在做请求准备,真正执行操作的是本篇文章要讲述的内容.正如标题一 ...
- nginx源码分析线程池详解
nginx源码分析线程池详解 一.前言 nginx是采用多进程模型,master和worker之间主要通过pipe管道的方式进行通信,多进程的优势就在于各个进程互不影响.但是经常会有人问道,n ...
- 【集合框架】JDK1.8源码分析之ArrayList详解(一)
[集合框架]JDK1.8源码分析之ArrayList详解(一) 一. 从ArrayList字表面推测 ArrayList类的命名是由Array和List单词组合而成,Array的中文意思是数组,Lis ...
- Sentinel源码解析四(流控策略和流控效果)
引言 在分析Sentinel的上一篇文章中,我们知道了它是基于滑动窗口做的流量统计,那么在当我们能够根据流量统计算法拿到流量的实时数据后,下一步要做的事情自然就是基于这些数据做流控.在介绍Sentin ...
- Spring源码之九finishRefresh详解
Spring源码之九finishRefresh详解 公众号搜索[程序员田同学],专职程序员兼业余写手,生活不止于写代码 Spring IoC 的核心内容要收尾了,本文将对最后一个方法 finishRe ...
随机推荐
- .net core下使用DbProviderFactories.GetFactory("")无法创建工厂的解决方案
前言:我们有时候会有一种需求,需要连接很多的数据库,如:mysql,sqlserver,oracle等等,需要把这些数据库里的数据抽取出来加工后,返回给客户端使用. 在.net framework中是 ...
- 获取给定地址中的域名,substring()截取
package seday01;/** * 获取给定地址中的域名 * @author xingsir */public class Test { public static void main(Str ...
- 浅谈Java中switch分支语句
前言: 在程序中遇到多分支选择的时候,想必大家都喜欢用if...else if...else...语句,尤其是初学者,因为在了解switch语句之前,我也是只会用if...else语句.那么现在看完这 ...
- CSS3 新增选择器
CSS3 新增选择器 结构(位置)伪类选择器(CSS3) :first-child :选取属于其父元素的首个子元素的指定选择器 :last-child :选取属于其父元素的最后一个子元素的指定选择器 ...
- ES6数组及对象遍历的新增方法 entries(),keys() 和 values()
ES6 提供三个新的方法——entries(),keys()和values()——用于遍历数组.它们都返回一个遍历器对象(详见<Iterator>一章),可以用for...of循环进行遍历 ...
- SAP MM MB5L 报表里的差异金额如何调整?
SAP MM MB5L 报表里的差异金额如何调整? 5月3号,收到财务顾问提出的一个问题,说是MB5L报表里有差异. 如下查询条件, 报表结果里显示有差异, 经查,导致这个差异的原因之一是,一些物料批 ...
- docker部署gitlab-ce
简介 环境准备 centos7 docker 1.13.1 gitlab-ce 安装步骤 1.首先需要从docker镜像仓库当中获取gitlab-ce的最新镜像文件,由于我本机已经获取了该镜像,所以在 ...
- mysql操作篇续
# ### part1. 数据类型 - 时间date YYYY-MM-DD 年月日 (纪念日)time HH:MM:SS 时分秒 (体育竞赛)year YYYY 年份值 (酒的年份,82年拉菲)dat ...
- 解压 Android 系统中的 system.img
本篇文章讲解 system.img 是什么东西,以及它的打包和解包方式 system.img 是什么 system.img 是 Android 系统中用来存放系统文件的镜像 (image) ,文件格式 ...
- python的gRPC示例
参考URL: https://segmentfault.com/a/1190000015220713?utm_source=channel-hottest gRPC 是一个高性能.开源和通用的 RPC ...