一文教会你认识Vuex状态机
摘要:简单来说,Vuex就是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。
本文分享自华为云社区《Vuex状态机快速了解与应用》,原文作者:北极光之夜。
一. 速识概念:
1. 组件之间共享数据的方式:
通常有以下几种方式:
- 父向子传值:v-bind 属性绑定;
- 子向父传值:v-on 事件绑定;
- 兄弟组件之间共享数据:EventBus;
2. vuex是什么:
- 按照官方的话来说,Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension (opens new window),提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
- 简单来说,Vuex就是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。
3.使用vuex优点:
- 能够在vuex中集中管理共享的数据,易于开发和后期维护。
- 能够高效地实现组件之间的数据共享, 提高开发效率。
- 存储在vuex中的数据都是响应式的,能够实时保持数据与页面的同步。
- 解决了非父子组件的消息传递(将数据存放在state中)。
- 减少了AJAX请求次数,有些情景可以直接从内存中的state获取。
一般情况下,只有组件之间共享的数据,才有必要存储到vuex中。而对于组件中的私有数据,就没必要了,依旧存储在组件自身的data中即可。当然,如果你想要都存在vuex中也是可以的。
二. 基本使用:
1.安装依赖包:
npm install vuex --save
2.导入依赖包:
import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex)
3.创建store对象:
import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex) const store = new Vuex.Store({
//state中存放的就是全局共享的数据
state: {
count: 0
}
})
4. 将store对象挂载到vue实例中:
new Vue({
el: '#app',
store
})
此时所有组件就可以从store中获取数据了。
三.创建项目:
下面为创建一个vue项目流程,后面会有案例:
(1)打开cmd窗口输入 vue ui 打开vue的可视化面板:
(2)选择新建项目路径:
(3)命名:
(4)手动选择配置,注意用的是vue2版本:
(5)创建:
(6)下一步:
(7)创建成功,到对应目录打开vscode开始编程:
(8)运行项目:
四. 讲解前提:
前提(注意):
写一个计数器小案例,从案例中配合概念能更快上手vuex。所以下面核心概念中的代码部分是基于这个小案例来演示的。目标:写两个子组件,有一个公共count值,在父组件中,其中一个组件实现点击后count值减1,一个组件实现点击后count值增1。
父组件 App.vue 初始代码:
<template>
<div id="app">
<my-add></my-add>
<p>--------------------</p>
<my-reduce></my-reduce>
</div>
</template> <script>
// 引入组件
import Add from './components/Add.vue'
import Reduce from './components/Reduce.vue'
export default {
name: 'App',
data() {
return { }
},
components: {
'my-add': Add,
'my-reduce': Reduce
} }
</script>
子组件Add.vue初始代码:
<template>
<div>
<p>count值为:</p>
<button>+1</button>
</div> </template>
<script>
export default{
data() {
return { }
},
}
</script>
子组件Reduce.vue初始代码:
<template>
<div>
<p>count值为:</p>
<button>-1</button>
</div>
</template>
<script>
export default{
data() {
return { }
},
}
</script>
store对象初始代码为:
import Vue from 'vue'
import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({
state: {
count: 0
}
})
初始效果:
五.核心概念:
1.state:
按照官方的话来说,如下:Vuex 使用单一状态树——是的,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。
简单来说,就是State提供唯一的公共数据源, 所有共享的数据都要统一放到Store的State中进行存储。
1.1 组件中访问state的第一种方式:
组件中直接输入以下命令:
如在Add.vue子组件中引用:
<template>
<div>
<p>count值为:{{this.$store.state.count}}</p>
<button>+1</button>
</div>
</template>
//下面部分代码跟前面一样无改变,所以省略了
看效果,显示了count的值为0:
1.2 组件中访问state的第二种方式:
(1)从 vuex 中按需导入 mapState 函数
import { mapState } from 'vuex'
(2)通过刚才导入的mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性:
computed: {
...mapState([count])
}
小知识:computed用来监控自己定义的变量,该变量不在data里面声明,直接在computed里面定义,然后就可以在页面上进行双向数据绑定展示出结果或者用作其他处理;
如在Reduce.vue子组件中引用:
<template>
<div>
<p>count值为:{{count}}</p>
<button>-1</button>
</div>
</template>
<script>
import {mapState} from 'vuex'
export default{
data() {
return { }
},
computed: {
...mapState(['count'])
}
}
</script>
看效果,同样显示了count的值为0:
2. mutation:
按照官方的话来说,更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
简单来说就是Mutation用于变更Store中的数据。
①只能通过mutation变更Store数据,不可以直接操作Store中的数据。
②通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化。
比如,要实现count值自增加1的操作,那就在先motations里定义一个自增加1的函数。然后对应子组件想用,该组件就直接引入mutation并调用对应的函数就好。
如下,Add.vue子组件要实现自增加1功能:先在状态机里的mutations里定义一个能实现自增的函数add:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
//自增加1函数
add(state){
state.count++
}
}
})
2.1 触发mutation的第一种方式:
Add.vue子组件里给按钮绑定点击事件,并触发mutation:
<template>
<div>
<p>count值为:{{this.$store.state.count}}</p>
<button @click="btnAdd">+1</button>
</div> </template>
<script>
export default{
data() {
return { }
},
methods: {
btnAdd() {
// 第一种引入mutation的方式,触发add函数
this.$store.commit('add')
}
}
}
</script>
看效果实现了点击自增:
2.2 触发mutation并传参数:
当然,当组件里调用mutation里函数时,也是可以传参数的。比如,有一个自增函数,但增多少看调用时传入的参数:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
// 传入参数,第一个一定是state,第二个为传入的参数
//自增加 n 的函数
addN(state,n){
state.count+= n
}
}
})
对应组件调用时要传入参数:
methods: {
btnAdd2() {
// 引入mutation的方式,触发addN函数
// 并传参,自增加6吧
this.$store.commit('addN',6)
}
}
2.3 触发mutation的第二种方式:
(1)从 vuex 中按需导入 mapMutations 函数
import { mapMutations } from 'vuex'
(2)通过刚才导入的mapMutations函数,将需要的mutations函数,映射为当前组件的methods方法:
methods: {
...mapMutations(['add','addN'])
}
实战,实现Reduce.vue组件的点击自减1的功能要求:
状态机添加自减函数:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
//自增加1函数
add(state){
state.count++
},
// 自减1的函数
sub(state){
state.count--
}
}
})
Reduce.vue组件点击按钮实现自减1:
<template>
<div>
<p>count值为:{{count}}</p>
<button @click="btnSub">-1</button>
</div>
</template>
<script>
//导入
import {mapState,mapMutations} from 'vuex'
export default{
data() {
return { }
},
computed: {
...mapState(['count'])
},
methods: {
// 映射mutation里的sub函数
...mapMutations(['sub']),
// 要自减,调用sub函数
btnSub(){
this.sub()
}
}
}
</script>
看效果:
3.Action:
至此,第四大点里的案例已经完成,已经实现了自增和自减,现在对案例做改进,要我们点击按钮一秒后再自增和自减,该怎么实现?可以在状态机里的mutation里的函数是加一个1秒定时器吗,这肯定是不行的,因为mutation里不支持异步操作,那咋办,当当当,Action闪亮登场。
Action 可以包含任意异步操作,所以它用来处理异步任务。
Action 提交的是 mutation,而不是直接变更状态。记住它并不能直接修改state里的数据,只有mutation能修改。就是说,如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据。
先在状态机里定义Action:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
//自增加1函数
add(state){
state.count++
},
// 自减1的函数
sub(state){
state.count--
}
},
// 定义action,里面的addAsync函数实现1秒后执行mutation里的add函数
actions: {
addAsync(context) {
setTimeout(()=>{
// 必须通过context.commit()触发mutation才行
context.commit('add')
},1000)
}
}
})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation。
3.1 触发Action的第一种方式:
更改组件Add.vue代码,引入Action,实现异步自增操作。
<template>
<div>
<p>count值为:{{this.$store.state.count}}</p>
<button @click="btnAdd">+1</button>
</div> </template>
<script>
export default{
data() {
return { }
},
methods: {
btnAdd() {
// 第一种引入Action的方式,触发addAsync函数
// 这里的dispatch专门用来调用action函数
this.$store.dispatch('addAsync')
}
}
}
</script>
看效果,实现1秒后自增:
3.2 触发Action异步任务并传参数:
当然,当组件里调用action里函数时,也是可以传参数的。比如,有一个点击1秒后才执行的自增函数,但增多少看调用时传入的参数:
定义:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
// 传入参数,第一个一定是state,第二个为传入的参数
//自增加 n 的函数
addN(state,n){
state.count+= n
}
},
actions: {
// 有参数 n,这个n又传给了mutation里的addN函数
addNAsync(context,n) {
setTimeout(()=>{
context.commit('addN',n)
},1000)
}
}
})
对应组件调用时要传入参数:
methods: {
btnAdd2() {
// 调用dispatch函数
// 触发action时传参数,为 6 吧,表示自增6
this.$store.dispatch('addNAsync',6)
}
}
3.3 触发Action的第二种方式:
(1)从 vuex 中按需导入 mapActions 函数
import { mapActions } from 'vuex'
(2)通过刚才导入的mapActions函数,将需要的actions函数,映射为当前组件的methods方法:
methods: {
...mapActions(['add','addN'])
}
实战,实现Reduce.vue组件的点击一秒后自减1的功能要求:
定义actions里的subAsync为一秒后自减函数:
export default new Vuex.Store({
state: {
count: 0
},
mutations: {
//自增加1函数
add(state){
state.count++
},
// 自减1的函数
sub(state){
state.count--
}
},
actions: {
addAsync(context) {
setTimeout(()=>{
context.commit('add')
},1000)
},
subAsync(context) {
setTimeout(()=>{
context.commit('sub')
},1000)
}
}
})
更改Reduce.vue代码,实现功能:
<template>
<div>
<p>count值为:{{count}}</p>
<button @click="btnSub">-1</button>
</div>
</template>
<script>
//导入
import {mapState,mapActions} from 'vuex'
export default{
data() {
return { }
},
computed: {
...mapState(['count'])
},
methods: {
// 映射Action里的函数
...mapActions(['subAsync']),
// 要自减,调用subAsync函数
btnSub(){
this.subAsync()
}
}
}
</script>
看效果:
4. Getter:
Getter用于对Store中的数据进行加工处理形成新的数据。且要注意的是它并不会修改state中的数据。
①Getter 可以对Store中已有的数据加工处理之后形成新的数据,类似Vue的计算属性。
②Store 中数据发生变化,Getter 的数据也会跟着变化。
如,有一个返回当前count+1的getter函数:
4.1 触发getters的第一种方式:
this.$store.getters.名称
在App.vue组件中显示:
<template>
<div id="app">
<my-add></my-add>
<p>--------------------</p>
<my-reduce></my-reduce>
<p>--------------------</p>
<h3>{{this.$store.getters.showNum}}</h3>
</div>
</template>
效果:
4.2触发getters的第二种方式:
(1)从 vuex 中按需导入 mapGetters 函数
import { mapGetters } from 'vuex'
(2)通过刚才导入的mapGetters函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性:
computed: {
...mapGetters(['showNum'])
}
还是在App.vue中使用把:
<template>
<div id="app">
<my-add></my-add>
<p>--------------------</p>
<my-reduce></my-reduce>
<p>--------------------</p>
<h3>{{showNum}}</h3>
</div>
</template> <script>
// 引入组件
import Add from './components/Add.vue'
import Reduce from './components/Reduce.vue'
// 导入 mapGetters函数
import {mapGetters} from 'vuex'
export default {
name: 'App',
data() {
return { }
},
components: {
'my-add': Add,
'my-reduce': Reduce
},
// 引入 getter
computed: {
...mapGetters(['showNum'])
} }
</script>
看,一样的效果:
一文教会你认识Vuex状态机的更多相关文章
- 修改vuex状态机中的数据
vuex状态机中的数据是必须提交mutation来修改,如果现实开发中,我们需要修改,而又不想提交mutaition,应该怎么做呢? 先来回顾一下场景,有一个列表是存在vuex中的 这个列表展 ...
- Vuex初识
vuex是vue中单向数据流的一个状态管理模式,它可以集中存储管理应用中所有组件的状态,并且有一套相应的规则可以去预测数据的变化.类似与此的还有react中的redux,dva等状态管理模式. 一般我 ...
- vuex入门教程和思考
Vuex是什么 首先对于vuex是什么,我先引用下官方的解释. Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可 ...
- Vue2.0 探索之路——vuex入门教程和思考
Vuex是什么 首先对于vuex是什么,我先引用下官方的解释. Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可 ...
- Vuex的基本原理与使用
我们需要知道 vue 是单向数据流的方式驱动的 什么是vuex? 为什么要使用vuex ? - 多个视图依赖于同一状态. - 来自不同视图的行为需要变更同一状态. vuex 类似Redux 的状态管理 ...
- Redux/Mobx/Akita/Vuex对比 - 选择更适合低代码场景的状态管理方案
近期准备开发一个数据分析 SDK,定位是作为数据中台向外输出数据分析能力的载体,前端的功能表现类似低代码平台的各种拖拉拽.作为中台能力的载体,SDK 未来很大概率会需要支持多种视图层框架,比如Vue2 ...
- 基于 Vuex 的时移操作(撤回/恢复)实现
最近做了一个 BI 平台的可视化看板编辑器,项目刚做完一期,各方面的功能都还能粗糙,但该有的也都有了,比如编辑器场景下最基本的两类时移操作-撤回(undo) 和恢复 (redo). 用 vuex 实现 ...
- 关于Vue.js 2.0 的 Vuex 2.0,你需要更新的知识库
应用结构 实际上,Vuex 在怎么组织你的代码结构上面没有任何限制,相反,它强制规定了一系列高级的原则: 应用级的状态集中放在 store 中. 改变状态的唯一方式是提交mutations,这是个同步 ...
- 适合WebApi的简单的C#状态机实现
目标 采用了Restful WebApi的架构,再把业务逻辑状态转移放到后端就有点违背初衷了.实际上只要后端Api的权限设置的好,把状态转移放到前端也未尝不可.我考虑的结果是,一般如果变更这个状态本身 ...
随机推荐
- hdu4862 费用流(不错)
题意: 给你一个矩阵,你最多可以选择k条路线,k条路线的起点随意,每次行走的距离随意,但是只能往右或者下走,走过的点不能再走,而且每一步如果a->b,如果a和b的权值s相等那么就可以 ...
- C++扫雷小游戏(基于CMD命令行)
这个小游戏是笔者在大一C语言课程设计的时候写的,基于命令行,为了显得漂亮一些,特别加上了彩色特效~~~ 注意:Win10系统须将命令行调为旧版命令行,否则有可能会显示乱码! 代码示例: #includ ...
- Python中的可迭代Iterable和迭代器Iterator
目录 Iterable可迭代对象 如何判断对象是否是可迭代对象Iterable Iterator迭代器 如何判断对象是否迭代器Iterator 将Iterable转换成Iterator Iterabl ...
- 内核模式下的线程同步的分析(Windows核心编程)
内核模式下的线程同步 内核模式下的线程同步是用户模式下的线程同步的扩展,因为用户模式下的线程同步有一定的局限性.但用户模式下线程同步的好处是速度快,不需要切换到内核模式(需要额外的 CPU 时间).通 ...
- Windows核心编程 第七章 线程的调度、优先级和亲缘性(下)
7.6 运用结构环境 现在应该懂得环境结构在线程调度中所起的重要作用了.环境结构使得系统能够记住线程的状态,这样,当下次线程拥有可以运行的C P U时,它就能够找到它上次中断运行的地方. 知道这样低层 ...
- 第六部分 数据搜索之使用HBASE的API实现条件查询
题目 使用HADOOP的MAPReduce,实现以下功能: (1)基于大数据计算技术的条件查询:使用mapreduce框架,实现类似Hbase六个字段查询的功能 (2)时段流量统计:以hh:mm:ss ...
- ThinkPHP5.1 输出到模板HTML格式被强行转成了字符
出现问题 控制器传给视图一个input标签,在视图页面显示出来就是 <input type='text'></input>,显示出来的是一个文本,而不是一个可以输入的文本框 解 ...
- php单列模式和工厂模式
一.单例模式又称为职责模式,它用来在程序中创建一个单一功能的访问点,通俗地说就是实例化出来的对象是唯一的.所有的单例模式至少拥有以下三种公共元素: 1. 它们必须拥有一个构造函数,并且必须被标记为pr ...
- Thinking in UML 笔记(一) -- 面向对象
一.UML 中最重要的就是面向对象. 面向对象的认识论可以构建更为复杂的系统来解释复杂的世界. 1. 面向过程,一切都是相互紧密地联系在一起,互相作用,互相影响. 2.面向对象, 世界是分割开的,只有 ...
- Java 并发编程(一) → LockSupport 详解
开心一刻 今天突然收到花呗推送的消息,说下个月 9 号需要还款多少钱 我就纳了闷了,我很长时间没用花呗了,怎么会欠花呗钱? 后面我一想,儿子这几天玩了我手机,是不是他偷摸用了我的花呗 于是我找到儿子问 ...