下班前几分钟,我学会了如何使用 Vuex
目录
前言
正文
一、基本概念
二、项目场景
三、如何使用
1、安装
2、State 初始值
3、Getters 修饰值
4、Mutations 修改值
5、Actions 异步修改值
四、总结
五、建议
何时使用 Vuex ?
前言
本人曾对 Vuex 作过详细介绍,但是今天去回顾的时候发现文章思路有些繁琐,不容易找到重点。于是,在下班前几分钟,我对其重新梳理了一遍。
tips:本文的案例均为Vue2版本。
正文
一、基本概念
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
二、项目场景
如果你的项目里有很多页面(组件/视图),页面之间存在多级的嵌套关系,此时,如果这些页面都需要共享一个状态的时候,此时就会产生以下两个问题:
多个视图依赖同一个状态
来自不同视图的行为需要变更同一个状态
解决方案(初版):
对于第一个问题,假如是多级嵌套关系,你可以使用父子组件传参进行解决,虽有些麻烦,但好在可以解决;对于兄弟组件或者关系更复杂组件之间,虽然可以通过各种各样的办法解决,可实在很不优雅,而且等项目做大了,代码量愈发巨大,实在令人心烦。
对于第二个问题,你可以通过父子组件直接引用,或者通过事件来变更或者同步状态的多份拷贝,但是这种模式很脆弱,使得代码难以维护,而且同样会让代码量剧增。
思路:
把各个组件都需要依赖的同一个状态抽取出来,全局统一管理。
在这种模式下,任何组件都可以直接访问到这个状态,或者当状态发生改变时,所有的组件都相应更新。
此时,Vuex 就诞生了。 这就是它背后的基本思想,借鉴了 Flux、Redux。与其他模式不同的是,Vuex 是专门为 Vue 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
三、如何使用
1、安装
进入项目,键入以下命令:
npm install vuex --save
2、State 初始值
在 src 路径下创建 store 文件夹,并在该文件夹下新增 index.js 文件:
import Vue from 'vue';
import Vuex from 'vuex';Vue.use(Vuex);const store = new Vuex.Store({state: {// 定义一个name,以供全局使用name: 'leo'}
});export default store;
修改 main.js:
import Vue from 'vue';
import App from './App';
import store from './store'; // 引入我们前面导出的store对象Vue.config.productionTip = false;new Vue({el: '#app',store, // 把store对象添加到vue实例上components: { App },template: '<App/>'
});
最后修改 App.vue:
<template><div></div>
</template><script>export default {mounted() {// 使用this.$store.state.xxx可以直接访问到仓库中的状态console.log(this.$store.state.name); // 'leo'}}
</script>
建议一:this.$store.state.xxx 放在计算属性中,这样可以让你的代码看起来更优雅一些。
export default {mounted() {console.log(this.getName); // 'leo'},computed:{getName() {return this.$store.state.name;}}
}
建议二:每次都写 this.$store.state.xxx 让你感到厌烦,造成代码冗余,可以使用 mapState。
<script>
import { mapState } from 'vuex'; // 从vuex中导入mapState
export default {mounted() {console.log(this.name); // 'leo'},computed: {...mapState(['name']) // 经过解构后,自动就添加到了计算属性中,此时就可以直接像访问计算属性一样访问它}
}
</script>
你甚至可以给它取别名:
...mapState({ userName: 'name' }) // 赋别名的话,这里接收对象,而不是数组
3、Getters 修饰值
设想一个场景,你已经将 store 中的 name 展示到页面上了,而且是很多页面都展示了,此时客户要求在每个 name 前都加上“hello”。
最容易想到的办法就是去每个用到 name 的页面一个一个加上“hello”,显然这种方式并不友好,原因如下:
第一,假如你在A、B、C三个页面都用到了 name,那么你要在这A、B、C三个页面都修改一遍,多个页面你就要加很多遍这个方法,造成代码冗余,很不好。
第二,假如下次客户让你把“hello”改成“greet”的时候,你又得把三个页面(甚至更多)都改一遍,这时候你是拿石头砸自己的脚。
吸取上面的教训,我们有一个新的思路:直接在 store 中对 name 进行一些操作或者加工,从源头解决问题!这时候,Getter 闪亮登场!
首先,在 store 对象中增加 getters 属性:
const store = new Vuex.Store({state: {name: 'leo'},// 在store对象中增加getters属性getters: {getMessage(state) { // 获取修饰后的name,第一个参数state为必要参数,必须写在形参上return `hello ${state.name}`;}}
});
在组件中使用:
export default {mounted() {console.log(this.$store.state.name);console.log(this.$store.getters.getMessage); // 注意不是$store.state了,而是$store.getters}
}
建议使用 mapGetters:
<script>
import { mapState, mapGetters } from 'vuex';
export default {mounted() {console.log(this.name); // 'leo'console.log(this.getMessage); // 'hello leo' },computed: {...mapState(['name']),...mapGetters(['getMessage'])},
}
</script>
你也可以给它取别名:
...mapGetters({ greetMsg: 'getMessage' }) // 赋别名的话,这里接收对象,而不是数组
4、Mutations 修改值
说到修改值,有的人可能会想到这样写:
this.$store.state.xxx = XXX;
首先,这是一种错误的写法。为什么说是错误的写法?因为这个 store 仓库比较奇怪,你可以随便拿,但是你不能随便改,举个例子:
假如你打开朋友圈,看到你的好友发了条动态,但是动态里有个错别字,你要怎么办呢?你可以帮他改掉吗?当然不可以!我们只能通知他本人去修改,因为是别人的朋友圈,你是无权操作的,只有他自己才能操作。同理,在 Vuex 中,我们不能直接修改仓库里的值,必须用 Vuex 自带的方法去修改。这个时候,Mutation 闪亮登场!
首先,修改 store/index.js:
const store = new Vuex.Store({state: {name: 'leo',number: 0,},mutations: { // 增加nutations属性setNumber(state) { // 增加一个mutations的方法,方法的作用是让number从0变成5,state是必须默认参数state.number = 5;}}
});
然后,修改 App.vue:
<script>
export default {mounted() {console.log(this.$store.state.number); // 旧值,0this.$store.commit('setNumber');console.log(this.$store.state.number); // 新值,5},
}
</script>
如果我们想传动态参数怎么办?
首先,修改 store/index.js:
const store = new Vuex.Store({state: {name: 'leo',number: 0,},mutations: {setNumber(state, num) { // 增加一个带参数的mutations方法state.number = num;},},
});
相应地,修改 App.vue:
<script>
export default {mounted() {console.log(this.$store.state.number); // 旧值,0this.$store.commit('setNumber', 666);console.log(this.$store.state.number); // 新值,666},
}
</script>
上面的这种传参的方式虽然可以达到目的,但是并不推荐。建议传递一个对象,看起来更美观,对象的名字你可以随意命名,一般命名为 payload:
mutations: {setNumber(state, payload) { // 增加一个带参数的mutations方法,并且官方建议payload为一个对象state.number = payload.number;},
},
相应地,修改 App.vue:
<script>
export default {mounted() {console.log(this.$store.state.number); // 旧值,0this.$store.commit('setNumber', { number: 666 }); // 调用的时候需要传递一个对象console.log(this.$store.state.number); // 新值,666},
}
</script>
建议使用 mapMutations:
<script>
import { mapMutations } from 'vuex';
export default {mounted() {this.setNumber({ number: 666 });},methods: { // 注意,mapMutations是解构到methods里面的,而不是计算属性了...mapMutations(['setNumber'])}
}
</script>
你也可以给它取别名:
methods:{...mapMutations({ changeNumber: 'setNumber' }) // 赋别名的话,这里接收对象,而不是数组
}
注意:Mutations 里面的函数必须是同步操作,不能包含异步操作。
Mutations 只能进行同步操作,所以,我们马上开始下一节,看看使用 Actions 进行异步操作的时候应该注意什么!
5、Actions 异步修改值
Vuex 不希望你将异步操作放在 Mutations 中,所以就给你设置了一个区域,让你进行异步操作,这就是 Actions。
首先,修改 store/index.js:
const store = new Vuex.Store({state: {name: 'leo',number: 0,},mutations: {setNumber(state, payload) {state.number = payload.number;},},actions: { // 增加actions属性setNum(content) { // 增加setNum方法,默认第一个参数是content,其值是复制的一份storereturn new Promise(resolve => { // 模拟异步操作,1秒后修改number为666setTimeout(() => {content.commit('setNumber', { number: 666 });resolve();}, 1000);});}}
});
然后,修改 App.vue:
async mounted() {console.log(this.$store.state.number); // 旧值,0await this.$store.dispatch('setNum'); // 等待异步操作完成console.log(this.$store.state.number); // 新值,666
}
其实 action 就是去提交 mutation 的。异步操作都在 action 中消化了,最后再去提交 mutation。
当然,你也可以进行动态传参。
首先,修改 store/index.js:
actions: {setNum(content, payload) { // 增加payload参数return new Promise(resolve => {setTimeout(() => {content.commit('setNumber', { number: payload.number });resolve();}, 1000);});},
}
相应地,修改 App.vue:
async mounted() {console.log(this.$store.state.number); // 旧值,0await this.$store.dispatch('setNum', { number: 888 });console.log(this.$store.state.number); // 新值,888
}
建议使用 mapActions:
<script>
import { mapActions } from 'vuex';
export default {methods: {...mapActions(['setNum']), // 解构到methods中},async mounted() {await this.setNum({ number: 888 }); // 直接调用即可}
}
</script>
你也可以给它取别名:
...mapActions({ changeNumber: 'setNum' }) // 赋别名的话,这里接收对象,而不是数组
tips:在 actions 里面,方法的形参可以直接将 commit 解构出来,方便后续操作。
actions: {setNum({ commit }) { // 直接将content结构掉,解构出commit,下面就可以直接调用了return new Promise(resolve => {setTimeout(() => {commit('xxx'); // 直接调用resolve();}, 1000);});},
},
四、总结
下班前这几分钟,你知道了如何使用 Vuex。你会安装它,配置它,读取 state 的值,甚至修饰读(Getters),然后你会修改里面的值(Mutations),如果有异步操作并且需要修改 state,那你就要使用 Actions。
一张神奇的图。
五、建议
何时使用 Vuex ?
这个问题因人而异,如果你不需要开发大型的单页应用,此时你完全没有必要使用 Vuex,比如你的页面就两三个,使用 Vuex 后增加的文件比你现在的页面还要多,完全没这个必要。
假如你的项目达到了中大型应用的规模,此时你很可能会考虑如何更好地在组件外部对状态进行统一管理,甚至会分模块(Vuex 中的 module,不展开),它将会是一个不错的选择。
下班前几分钟,我学会了如何使用 Vuex相关推荐
- 下班前几分钟,我彻底弄懂了 undefined 和 null 的区别
目录 前言 一.基本概念 1.undefined 2.null 二.简单区别 三.表现形式 1.typeof 2.== 与 === 3.Object.prototype.toString.call 4 ...
- 下班前几分钟,逮到一个腾讯10年老测试开发,聊过之后彻底悟了...
优秀的人真的是比比皆是,不比不知道,一比吓一跳 老话说的好,这人呐,一单在某个领域鲜有敌手了,就会闲得蛋疼.就在昨天下班的前几分钟认识了一个在阿里工作了 10 年的测试开发,因为本人天赋比较高,平时工 ...
- 下班前几分钟,我彻底弄懂了并查集
目录 一.并查集的由来 二.代表元法 2.1 初始化 2.2 查询 2.3 合并 2.4 设计理念 三.并查集的应用 3.1 合并集合 3.2 连通块中点的数量 3.3 亲戚 3.4 省份数量 Ref ...
- 下班前10分钟光速安装skywalking并解决报错
看标题就知道我当时慌的一批 下载方式 可以从官网下载apache-skywalking-apm-$version.tar.gz包.在windows或linux下都可以解压,因为运行参数需要指定里面的j ...
- 趁着下班前五分钟书写——Vue3通讯(常规写法、语法糖、v-modle、兄弟通讯)
回顾 前期 [科技与狠活]-- JS实现页面阻塞三秒_0.活在风浪里的博客-CSDN博客_js实现阻塞while 循环 及 do while 的使用, 利用循环实现伪暂停进程 n 秒https: ...
- 只要5分钟!学会自己打造多系统合集的DVD安装光盘
只要5分钟!学会自己打造多系统合集的DVD安装光盘(Windows All In One DVD ) 一.准备工作--需要软件 1. UltraISO(软碟通) v8.1.2.1625 下载:[url ...
- 快速学完计算机网络,如何让电脑网速变快 5分钟就学会
如何让电脑网速变快 5分钟就学会 电脑有时候网速太卡,许多人都会想把电脑拿扔了.但是小编今天教你怎么让网速变快.首先在电脑上选择开始后在选择运行,如下图 如何让电脑网速变快 5分钟就学会 第二:输入: ...
- pythonturtle简单绘图_10分钟轻松学会 Python turtle 绘图
10分钟轻松学会 Python turtle 绘图 python2.6版本中后引入的一个简单的绘图工具,叫做海龟绘图(Turtle Graphics),turtle库是python的内部库,使用导入即 ...
- 一分钟学会看k线图_一分钟怎样学会看k线图(纯干货)散户必备!
原标题:一分钟怎样学会看k线图(纯干货)散户必备! K线图最早是日本德川幕府时代大阪的米商用来记录当时一天.一周或一月中米价涨跌行情的图示法,后被引入股市.K线图有直观.立体感强.携带信息量大的特点, ...
最新文章
- 那些在学习iOS开发前就应该知道的事(part 1)
- 算法笔记之回溯法(2)
- elasticsearch搜素关键字自动补全(suggest)
- python 读取excel太慢_Python 读取excel并转换为字典
- java修改默认字符编码_设置默认的Java字符编码?
- 漫步最优化四十四——基本拟牛顿法
- NET-由于该控件目前不可见、未启用或类型不允许,因此无法将焦点移向
- [Oracle] SQL*Loader 详细使用教程(3)- 控制文件
- 怎么在条码打印软件中修改数据库连接
- vim 的配置详解/键盘映射配置详解
- 路由器硬改+刷OpenWrt+挂载摄像头+U盘
- java 图片深度_图像的色彩值称为图像的颜色深度,黑白图像的颜色深度为( )位。...
- 利用函数wavread对语音信号进行采样_信号时间采样
- Web安全——同源策略理解
- 密立根油滴实验的c语言程序,密立根油滴实验数据处理程序c++
- 8.2 JVM命令行监控——jstat
- 关于Java线程,看这一篇就绝对够用了
- table隐藏列与colgroup标签
- cmd 添加端口映射
- 阅读《A2-RL: Aesthetics Aware Reinforcement Learning for Image Cropping Debang》