一,前言

上一篇,主要介绍了 Vuex 中 getters 的实现,主要涉及以下几个点:

  • 将选项中的 getters 方法,保存到 store 实例中的 getters 对象中;
  • 借助 Vue 原生 computed,实现 Vuex 中 getters 的数据缓存功能;

本篇,继续介绍 Vuex 中 Mutations 的实现;


二,前文回顾

在前面介绍了 Vuex 的基本使用:

mutation:

  • 同步更新 state 状态;
  • 通过 $store.commit(type, payload)调用 mutations 中对应的方法;
    action:
  • 异步更新 state 状态;
  • 通过 $store.dispatch(type, payload)调用 actions 中对应的方法;
  • 在 action 方法中,可以进行异步请求操作;
  • 在 action 方法中,可以继续执行 dispatch 方法,调用其他 action 方法;
  • 在 action 方法中,可以多次调用 commit 方法,执行状态更新操作;
// App.vue<template><div id="app">商品数量: {{this.$store.state.num}} 个<br>商品单价: 10 元<br>订单金额: {{this.$store.getters.getPrice}} 元<br><button @click="$store.commit('changeNum',5)">同步更新:数量+5</button><button @click="$store.dispatch('changeNum',-5)">异步更新:数量-5</button></div>
</template>

在 Store 容器中,mutations 和 actions 相关配置如下:

// src/store/index.jsimport Vue from 'vue';
import Vuex from '@/vuex';Vue.use(Vuex);const store = new Vuex.Store({state: {num: 10},getters: {getPrice(state) {return state.num * 10}},// 同步更新状态mutations: {changeNum(state, payload) {state.num += payload;}},// 可执行异步操作,通过 mutations 更新状态actions: {changeNum({ commit }, payload) {setTimeout(() => {commit('changeNum', payload)}, 1000);}}
});
export default store;

三,Mutations 的实现

1,将 options.mutations 中定义的方法,绑定到 store 实例中的 mutations 对象

// src/vuex/store.jsexport class Store {constructor(options) { // options:{state, mutation, actions}// 声明 store 实例中的 mutations 对象this.mutations = {};// 获取 options 选项中的 mutations 对象const mutations = options.mutations;// 将 options.mutations 中定义的方法,绑定到 store 实例中的 mutations 对象Object.keys(mutations).forEach(key => {// payload:commit 方法中调用 store 实例中的 mutations 方法时传入this.mutations[key] = (payload) => mutations[key](this.state, payload);});}
}

2,创建并实现 commit 方法

1)用户可以在页面执行调用 store 实例中的 commit 方法:

<button @click="$store.commit('changeNum',5)">同步更新:数量+5</button>

2)也可以在 action 方法中,解构 store 实例中的 commit 方法:

// src/store/index.jsactions: {changeNum({ commit }, payload) {setTimeout(() => {commit('changeNum', payload)}, 1000);}}

基于以上两种使用场景,创建 commit 方法,为了确保 this 指向 store 实例,commit 方法使用箭头函数:

// src/vuex/store.js/*** 通过 type 找到 store 实例的 mutations 对象中对应的方法,并执行*    用户可能会解构使用{ commit }, 也有可能在页面使用 $store.commit,*    所以,在实际执行时,this是不确定的,{ commit } 写法 this 为空,*    使用箭头函数:确保 this 指向 store 实例;* @param {*} type mutation 方法名* @param {*} payload 载荷:值或对象*/commit = (type, payload) => {// 执行 mutations 对象中对应的方法,并传入 payload 执行this.mutations[type](payload)}

当调用 commit 方法时,会根据传入的 type 值(即选项中定义的 mutation 方法名)到 store 实例中的 mutations 对象找到对应的方法(即选项中定义的 mutation 方法),传入 state 和 payload 执行此方法,实现状态的同步更新;

// src/store/index.jsnew Vuex.Store({...mutations: {changeNum(state, payload) {console.log(`进入 mutations-changeNum:state = ${JSON.stringify(state)}, payload = ${payload}`)state.num += payload;}}...
});

测试同步更新,查看控制台输出:

打印 log,执行 mutation 方法;

同时,响应式数据的变化,触发了依赖收集中相关视图的更新渲染;


四,Actions 的实现

对比 dispatch 和 commit 两个方法,可以看出,参数是一致的,实现方法也大致相同:

<button @click="$store.commit('changeNum',5)">同步更新:数量+5</button>
<button @click="$store.dispatch('changeNum',-5)">异步更新:数量-5</button>

1,将 options.actions 中定义的方法,绑定到 store 实例中的 actions 对象

这部分逻辑和 Mutations 是完全一致的

// src/vuex/store.jsexport class Store {constructor(options) {// 声明 store 实例中的 actions 对象this.actions = {};// 获取 options 选项中的 actions 对象const actions = options.actions;// 将 options.actions 中定义的方法,绑定到 store 实例中的 actions 对象Object.keys(actions).forEach(key => {// payload:dispatch 方法中调用 store 实例中的 actions 方法时传入this.actions[key] = (payload) => actions[key](this, payload);});}

2,创建并实现 dispatch 方法

1)用户可以在页面执行调用 store 实例中的 dispatch 方法:

<button @click="$store.dispatch('changeNum',-5)">异步更新:数量-5</button>

2)也可以在 action 方法中,解构 store 实例中的 dispatch 方法:

// src/store/index.jsactions: {changeNum({ commit, dispatch }, payload) {setTimeout(() => {commit('changeNum', payload)}, 1000);}}

基于以上两种使用场景,创建 dispatch 方法,为了确保 this 指向 store 实例,dispatch 方法使用箭头函数:

// src/vuex/store.js/*** 通过 type 找到 store 实例的 actions 对象中对应的方法,并执行*    用户可能会解构使用{ dispatch }, 也有可能在页面使用 $store.dispatch,*    所以,在实际执行时,this 是不确定的,{ dispatch } 写法 this 为空,*    使用箭头函数:确保 this 指向 store 实例;* @param {*} type action 方法名* @param {*} payload 载荷:值或对象*/dispatch = (type, payload) => {// 执行 actions 对象中对应的方法,并传入 payload 执行this.actions[type](payload)}

当调用 dispatch 方法时,会根据传入的 type 值(即选项中定义的 action 方法名)到 store 实例中的 actions 对象找到对应的方法(即选项中定义的 action 方法),传入 store实例 和 payload 执行此方法,实现状态的同步更新;

同时,在 action方法中可以再次执行 dispatch 方法执行其他异步操作,也可以多次执行 commit 执行状态的更新操作;

// src/store/index.jsnew Vuex.Store({...actions: {changeNum({ commit }, payload) {console.log(`进入 actions-changeNum:commit = ${JSON.stringify(commit)}, payload = ${payload}`)setTimeout(() => { // 模拟异步commit('changeNum', payload)}, 1000);}}...
});

测试异步更新,查看控制台输出:

打印 log,先执行 action 方法,再通过 commit 执行 mutation 方法;

同时,响应式数据的变化,触发了依赖收集中相关视图的更新渲染;


五,对比 Mutations 和 Actions

通过以上 Mutations 和 Actions 实现可以看出,不管是同步还是异步更新 State 状态,做种都必须通过 commit 调用 mutation 方法,完成状态的更新操作;

这也使得 Vuex 状态的变更能够被 devtools 所跟踪和记录,实现了状态的统一管理;

再次强调,只能通过 mutation 方法才可以更新 Vuex 中的状态;


六,结尾

本篇,主要介绍了 Vuex 中 Mutations 和 Actions 的实现,主要涉及以下几个点:

  • 将 options 选项中定义的 mutation 方法绑定到 store 实例的 mutations 对象;
  • 创建并实现 commit 方法;
  • 将 options 选项中定义的 action 方法绑定到 store 实例的 actions 对象;
  • 创建并实现 dispatch 方法;

至此,一个简易版的 Vuex 状态管理插件就完成了;

8 月更文的 31 篇文章就算水完了;9 月开始 Vue2.x 源码的第二轮学习-文章优化;Vuex 下半部分将暂时搁置一段时间;

【手写 Vuex 源码】第五篇 - Vuex 中 Mutations 和 Actions 的实现相关推荐

  1. 【手写 Promise 源码】第八篇 - 完善 Promise 并通过 promise-aplus-tests 测试

    一,前言 上一篇,实现 Promise 对返回值 x 各种情况的分析和处理,主要涉及以下几个点: 回顾了相关的 Promise A+ 规范内容: 根据 Promise A+ 规范描述和要求,实现了核心 ...

  2. Node进阶——之事无巨细手写Koa源码

    作者 rocYoung Koa是一个基于Node.js的Web开发框架,特点是小而精,对比大而全的Express(编者按:此处是相对来说,国内当然是有Egg.js和ThinkJS),两者虽然由同一团队 ...

  3. Node进阶—事无巨细手写Koa源码

    作者 rocYoung Koa是一个基于Node.js的Web开发框架,特点是小而精,对比大而全的Express(编者按:此处是相对来说,国内当然是有Egg.js和ThinkJS),两者虽然由同一团队 ...

  4. node进阶——之事无巨细手写koa源码(转)

    https://juejin.im/post/5ba48fc4e51d450e704277fa koa是一个基于nodejs的web开发框架,特点是小而精,对比大而全的express,两者虽然由同一团 ...

  5. java 手写签名,signature java html5+ 手写签名 源码 Develop 238万源代码下载- www.pudn.com...

    文件名称: signature下载 收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 491 KB 上传时间: 2013-08-03 下载次数: 17 提 供 者: 孙晨 ...

  6. 跨年巨作 13万字 腾讯高工手写JDK源码笔记 带你飙向实战

    灵魂一问,我们为什么要学习JDK源码? 当然不是为了装,毕竟谁没事找事虐自己 ... 1.面试跑不掉.现在只要面试Java相关的岗位,肯定或多或少会会涉及JDK源码相关的问题. 2.弄懂原理才不慌.我 ...

  7. 手写Mybatis源码(原来真的很简单!!!)

    目录 一.JDBC操作数据库_问题分析 二.自定义持久层框架_思路分析 三.自定义框架_编码 1.加载配置文件 2.创建两个配置类对象 3.解析配置文件,填充配置类对象 4.创建SqlSessionF ...

  8. 【Java进阶营】膜拜 13万字 腾讯高工手写JDK源码笔记带你飙向实战

    灵魂一问,我们为什么要学习JDK源码? 当然不是为了装,毕竟谁没事找事虐自己 - 1.面试跑不掉.现在只要面试Java相关的岗位,肯定或多或少会会涉及JDK源码相关的问题. 2.弄懂原理才不慌.我们作 ...

  9. react学习笔记 react-router-dom react-redux基础使用及手写基础源码 组件反射 react原理

    vdom diff 高效的diff算法 新老vdom树比较 更新只需要更新节点 数据变化检测 batch dom读写 组件多重继承 //parent components export default ...

  10. 安卓手写字迹源码(毛笔,喷枪,马克笔等效果)

    之前项目需要,要在手机上实现笔迹的效果,这类的应用多了,但是源码在全球最大局域网内却找不到~~ 一年前是想着自己做的,当时知道安卓设备的touch是可以获取伪压力感应值 即手指压力越大,皮肤接触面积也 ...

最新文章

  1. linux 配置计算机和用户免密在本地计算机执行远程命令 hosts.equiv $HOME/.rhosts 简介
  2. 《Python从小白到大牛》第7章 运算符
  3. cassandra百亿级数据库迁移实践
  4. 面试问烂的 MySQL 四种隔离级别,看完吊打面试官!
  5. uni-app——map组件路线[polyline]功能示例
  6. 在一个电子商务网站应用中,涉及的实体信息类有很多,比如用户类User和用户地址类Address; 而每一个实体类的对象信息要存储到相应的数据库表中,如userTable和addressTable。
  7. Android之运行app提示The application could not be installed: INSTALL_FAILED_TEST_ONLY
  8. Hexo博客:您备案的网站未指向阿里云国内节点(不含香港)服务器,备案号可能被取消接入
  9. 从司法领域看阿里云产业AI策略:生态联盟,技术赋能
  10. mac php 停用,Mac_MAC系统 Apple ID 停用的解决办法,  一些MAC用户发现自己的Appl - phpStudy...
  11. java chatat delete,StringBuffer deleteCharAt(int index)
  12. Report machine 单据报表设计
  13. 大型油烟机清洗机器人_餐饮业大型油烟机清洗的必要性,你知道吗?
  14. PHP怎么做成Qq空间相册,美化QQ空间相册的照片4步走 让你轻松学会PS
  15. C语言实现系统日历查询系统
  16. 爬虫之爬取图片(运用了bs4和正则查取)
  17. Ip可视一键对讲机特点
  18. 【三年面试五年模拟】算法工程师的独孤九剑秘籍(前十二式汇总篇)V1版
  19. 如何应对“改变现状”的失败
  20. HANA用户权限设置

热门文章

  1. Spring的IOC原理(通俗易懂)
  2. 历史学习/科普知识宣传——闯关答题小程序
  3. 解决spyder闪退问题
  4. java计算机毕业设计高校助学金管理系统源码+mysql数据库+系统+lw文档+部署
  5. 花菁荧光染料Cy3/Cy5/Cy7标记COX-2环氧合酶,Cy3/Cy5/Cy7-Cyclooxygenase-2
  6. Vue项目如何引入JQuery详细步骤
  7. TypeError: Cannot interpret ‘4‘ as a data type || 创建 元素满足正态分布的矩阵 || 广播 || .zeros() || .ones()
  8. 自定义ZuulFilter用于验证生成的token
  9. 【动态规划】游艇租用问题(c++)
  10. [PMML] LightGBM模型保存为PMML文件,通过Java或者Python调用