最近公司项目中使用Vuex做状态管理,就全面温习了一遍文档,然后在项目使用中遇到一些常见问题就一一总结下。

一、由来

我们知道Vue中数据是自顶向下单向流动的,但是以下两种情况单向数据流实现起来十分繁琐且不易维护:

  1. 多个视图依赖同一状态;
  2. 来自不同视图需要变更统一状态。

因此,Vuex诞生了。我们需要把不同组件的共享状态抽离出来,放在全局单例中管理,这样我们的组件树构成一个巨大的“视图网”,任何组件都可以获取共享状态并且以相同的规则变更状态。

Vuex都有一个“store”,包含应用中大部分状态。Vuex和全局对象有以下两点不同

  1. Vuex中的状态是响应式的,只要store中的状态发生改变,其他组件也会得到高效更新;
  2. 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时注意以下事项:

  1. 最好提前在你的 store 中初始化好所有所需属性;
  2. mutation必须是同步函数;
  3. 当需要在对象上添加新属性时,你应该:
  • 使用 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,不同之处在于:

  1. action提交的是mutation,而不是直接变更状态,无法直接操作state;
  2. 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学习心得的更多相关文章

  1. 我的MYSQL学习心得(一) 简单语法

    我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  2. 我的MYSQL学习心得(二) 数据类型宽度

    我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  3. 我的MYSQL学习心得(三) 查看字段长度

    我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(五) 运 ...

  4. 我的MYSQL学习心得(四) 数据类型

    我的MYSQL学习心得(四) 数据类型 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(五) 运 ...

  5. 我的MYSQL学习心得(五) 运算符

    我的MYSQL学习心得(五) 运算符 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据 ...

  6. 我的MYSQL学习心得(六) 函数

    我的MYSQL学习心得(六) 函数 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  7. 我的MYSQL学习心得(七) 查询

    我的MYSQL学习心得(七) 查询 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

  8. 我的MYSQL学习心得(八) 插入 更新 删除

    我的MYSQL学习心得(八) 插入 更新 删除 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得( ...

  9. 我的MYSQL学习心得(九) 索引

    我的MYSQL学习心得(九) 索引 我的MYSQL学习心得(一) 简单语法 我的MYSQL学习心得(二) 数据类型宽度 我的MYSQL学习心得(三) 查看字段长度 我的MYSQL学习心得(四) 数据类 ...

随机推荐

  1. 简单web性能测试工具——ab命令(ApacheBench)

    ab命令(ApacheBench) ----------转载内容 ApacheBench(即ab)通常用来做网站性能压力测试,是性能调优过程中必不可少的一环,ab命令会创建很多的并发访问线程,模拟多个 ...

  2. 今天还是python游戏

    话不多说,上源码: import random, pygame, sys from pygame.locals import * FPS = 30 # frames per second, the g ...

  3. js 单引号和双引号相互替换的实现方法

    1.双引号替换成单引号 var domo = JSON.stringify(address).replace(/\"/g,"'"); var a = {a:1,b:2}; ...

  4. shell 大型脚本工具开发实战

    拆分脚本功能,抽象函数 1.function get_all_group 返回进程组列表字符串 2.function get_all_process 返回进程名列表字符串"nginx htt ...

  5. Linux文件(夹)属性

    ll  或者 ls -lh 查看文件属性:

  6. Vue框架之vuex的使用

    1.首先需要在你的项目目录下安装vuex 终端命令: 2.在全局组件中导入与声明vuex 3.创建store实例对象 let store = new Vuex.store({ state:{ }, m ...

  7. Vue框架之组件与过滤器的使用

    一.组件的使用 局部组件的使用 ​ 打油诗: 1.声子 2.挂子 3.用 var App = { tempalte:` <div class='app'></div>` }; ...

  8. CentOS7.X+LAMP+zabbix4.2环境下搭建Grafana6.1数据库可视化

    1.GrafanaRPM包部署(yum  install  wget) wget https://dl.grafana.com/oss/release/grafana-6.1.4-1.x86_64.r ...

  9. 华为SDN:解决传统网络3大问题

    转:http://mp.ofweek.com/tele/a145613326756 科技潮人 2013-08-05 14:20 传统网络之困 互联网爆炸式增长,除了规模和发展速度远超之前所有曾出现的数 ...

  10. java后端处理高并发

    一个登陆页面可能会被很多账户同时登陆或者注册,那么我们就好处理这些并发,否则降低程序的使用率,甚至程序奔溃,下面一段代码处理程序的高并发效果不错. /** *@author xiaoxie *@dat ...