Vuex学习心得
最近公司项目中使用Vuex做状态管理,就全面温习了一遍文档,然后在项目使用中遇到一些常见问题就一一总结下。
一、由来
我们知道Vue中数据是自顶向下单向流动的,但是以下两种情况单向数据流实现起来十分繁琐且不易维护:
- 多个视图依赖同一状态;
- 来自不同视图需要变更统一状态。
因此,Vuex诞生了。我们需要把不同组件的共享状态抽离出来,放在全局单例中管理,这样我们的组件树构成一个巨大的“视图网”,任何组件都可以获取共享状态并且以相同的规则变更状态。
Vuex都有一个“store”,包含应用中大部分状态。Vuex和全局对象有以下两点不同
- Vuex中的状态是响应式的,只要store中的状态发生改变,其他组件也会得到高效更新;
- store中的状态不能直接改变,只能显式的提交mutation来更新。
二、概念
State
Vuex使用单一状态树,state作为应用的唯一数据源而存在。当我们需要从store获取状态时,只需在组件计算属性中直接返回即可。使用mapState辅助函数可以更方便我们生成计算属性。
state.js
const state = {
count: 0
} export default state
component.js
import { mapState } from 'vuex'
export default {
name: 'Vuex',
data() {
return {
}
},
computed: {
localComputed: () => {},
...mapState({
count: state => state.count
})
},
methods: {
}
}
Vuex并不意味着所有状态都必须放在store中,若有些状态属于单个组件,最好作为组件的局部状态存在为好。
Getters
getter通俗来讲就是state的计算属性,方便我们从state中派生出一些状态出来。getter接受state、getter作为其第一个、第二个参数。
const getters = {
derCount: state => {
return state.count+1
},
doneLists: (state, getters) => {
return state.todoLists.filter(list => list.status)
},
todoCount: (state, getters) => {
return state.todoLists.length - getters.doneLists.length
},
} export default getters
获取getter对象可通过属性访问this.$store.getters.doneLists,同样我们可以通过mapGetters辅助函数获取:
...mapGetters([
'doneLists',
'todoCount'
])
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,只有mutation中才能直接操作state。Vuex 中的 mutation 非常类似于事件,不能直接调用mutation handler。你需要先在mutattion中注册handler,然后在action或组件中调用此函数。每个mutation接受state,payload作为其第一个、第二个参数。
const mutations = {
addCount: (state) => {
state++
},
updateList: (state, index) => {
let updateList = state.todoLists[index]
let status = updateList.status
status = status?0:1
state.todoLists[index].status = status
}
} export default mutations
Vuex的store是响应式的,因此使用mutation时注意以下事项:
- 最好提前在你的 store 中初始化好所有所需属性;
- mutation必须是同步函数;
- 当需要在对象上添加新属性时,你应该:
- 使用
Vue.set(obj, 'newProp', 123)
, 或者 - 以新对象替换老对象。例如,利用 stage-3 的对象展开运算符我们可以这样写:
state.obj = { ...state.obj, newProp: 123 }
你可以在组件中使用 this.$store.commit('xxx')
提交 mutation,或者使用 mapMutations
辅助函数将组件中的 methods 映射为 store.commit
methods: {
localMethods() { },
...mapMutations([
'updateList',
'addCount'
])
}
Action
action类似于mutation,不同之处在于:
- action提交的是mutation,而不是直接变更状态,无法直接操作state;
- action支持异步操作。
action函数接受和store相同属性、方法的context对象,同样支持提交载荷方式。action通过store.dispatch的方式来分发。
const actions = {
addCountAsync: ({commit}) => {
commit('addCount')
},
deleteListAsync: ({commit}, index) => {
setTimeout(() => {
commit('deleteList',index)
},1000)
}
} export default actions
你在组件中使用 this.$store.dispatch('xxx')
分发 action,或者使用 mapActions
辅助函数将组件的 methods 映射为 store.dispatch
调用(需要先在根节点注入 store
)
...mapActions([
'addCountAsync',
'deleteListAsync' //将this.deleteListAsync()映射为this.$store.dispatch('deleteListAsync')
]),
Module
Vuex是单一状态树,应用所有状态都集中在一个比较大的对象中。当项目足够大时,store对象会变得很臃肿。Vuex允许我们分割store为子模块,每个modules都拥有自己的state、getters、mutations、actions、mudules。
如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true
的方式使其成为带命名空间的模块。
- getter接受参数依次为局部state、getters、根节点状态rootState、根节点rootGetter;
- mutation局部状态state、payload作为第一、第二个参数;
- action局部状态为context.state,根节点状态为context.rootState。{state,commit,rootState,rootGetters};
const state = {
bookLists: [
{name: '三国演义', status: 1},
{name: '西游记', status: 1},
{name: '红楼梦', status: 0},
{name: '水浒传', status: 0}
]
} // getters
const getters = {
/**
* @param {[type]} state、getters [局部状态]
* @param {[type]} rootState、rootGetters [根节点状态]
*/
readBook: (state, getters, rootState, rootGetters) => {
return state.bookLists.filter(list => list.status)
}
} // mutations
const mutations = {
// state 局部状态
readOver (state, { index }) {
state.bookLists[index].status = 1
},
reRead (state, { index }) {
state.bookLists[index].status = 0
},
delete (state, { index }) {
state.bookLists.splice(index, 1)
}
} // actions
const actions = {
/**
* dispatch、commit局部化
* 提交是接受root访问根dispatch、commit
*/
deleteAsync ({ dispatch, commit, state, getters, rootState, rootGetters }, index) {
commit('delete',{index:index})
commit('reduceLast',null,{root:true})
}
} export default {
namespaced: true,
state,
getters,
mutations,
actions
}
若在子模块内部想在全局命名空间提交commit、分发action,将{root:true}作为第三参数传给commit、dispatch即可。
当在组件中使用带命名空间的子模块时,可以将空间名称作为第一参数传给相应map函数:
computed:
...mapState('book', {
bookLists: state => state.bookLists,
}),
methods:
...mapMutations('book', [
'readOver',变更状态
'reRead'
]),
...mapActions('book', [
'deleteAsync',
]),
三、使用技巧
在严格模式下使用Vuex时,使用v-model将state与表单绑定,修改表单值会出现报错。严格模式规定无论何时修改state状态且不是由于mutation引起就会抛出错误。这时我们可以在组件中将所需状态深拷贝一份,进行模板渲染或操作变更,最后再深拷贝一份提交mutation变更状态。这样组件内的操作就不受state影响。
获取深拷贝状态:
stateData() {
let _stateData = JSON.parse(JSON.stringify(this.$store.state.stateData))
this.data = _stateData
return this.$store.state.stateData
}
提交mutation:
setData(data) {
let setData = JSON.parse(JSON.stringify(data))
this.$store.commit('setStateData',setData)
}
Vuex学习心得的更多相关文章
- 我的MYSQL学习心得(一) 简单语法
我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(二) 数据类型宽度
我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(三) 查看字段长度
我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(四) 数据类型
我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...
- 我的MYSQL学习心得(五) 运算符
我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...
- 我的MYSQL学习心得(六) 函数
我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
- 我的MYSQL学习心得(七) 查询
我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
- 我的MYSQL学习心得(八) 插入 更新 删除
我的MYSQL学习心得(八) 插入 更新 删除 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得( ...
- 我的MYSQL学习心得(九) 索引
我的MYSQL学习心得(九) 索引 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...
随机推荐
- Windows下的Android Studio环境搭建、安装使用
https://jingyan.baidu.com/article/20b68a88ff2ca4796cec6232.html https://blog.csdn.net/jklinux/articl ...
- LeetCode每日一练(1-3)
题目导航 1. 两数之和 2. 两数相加 3. 无重复字符的最长子串 1. 两数之和 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的 ...
- Vue.use()源码分析且执行后干什么了
直接开始分析源码 // Vue源码文件路径:src/core/global-api/use.js import { toArray } from '../util/index' //initUse函数 ...
- iOS NSString使用stringWithFormat的拼接
##保留2位小数点## //.2代表小数点后面保留2位(2代表保留的数量) NSString *string = [NSString stringWithFormat:@"%.2f" ...
- 使用abapGit在ABAP On-Premises系统和SAP云平台ABAP环境之间进行代码传输
SAP ABAP顾问朋友们,应该都使用过SAPLink这个工具.如果两个ABAP Netweaver系统没有建立起传输路径时,我们无法使用标准的SE10事务码创建传输请求的方式进行这两个系统间的代码传 ...
- python selectors模块实现 IO多路复用机制的上传下载
import selectorsimport socketimport os,time BASE_DIR = os.path.dirname(os.path.abspath(__file__))''' ...
- Linux中关于dns配置的小记
一. 如上图 我当时的网卡配置文件里是静态模式,然后DNS1=114.114.114.114. 就是纳闷,这是为什么 随后,我又是将网卡配置文件,修改为DNS1=114.114.114.113. 重启 ...
- mysql案例分析
工作中,需要设计一个数据库存储,项目的需求大致如下: (1)对于每个用户,需要存储一个或多个库, 每个库, 由一个用户标识来标识,这里成为clientFlag. (2) 对于每一个库,结构如下: 1) ...
- Linux系统中安装软件的几种方式
转载:https://blog.csdn.net/qq_36119192/article/details/82866329 好长时间没有静下心来学习一下linux了 最近对linux安装软件有了点小小 ...
- KVM虚拟化——简介
KVM 基于内核的虚拟机KVM(Kernel-Based Virtual Machine)是2007年问世的开源虚拟化解决方案.KVM需要两个条件: ①硬件支持全虚拟化 ②操作系统为Linux KVM ...