vuex的各大属性详细讲解

认识Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。其作用是将一些重复性的状态放到一起统一管理,方便后期维护。假如你所负责的项目很小,只有个别几个功能,推荐不使用vuex。反之如果项目庞大,逻辑复杂,这时候就会出现一些状态在多个地方同事出现并复用的情况,这种情况下推荐使用vuex将他们统一管理,后期维护只需要更改vuex管理仓库即可。
在这里插入图片描述
由图可见,在Vuex这个闭环中改变其中的数据需要走一个循环。

Vuex项目构建

首先,在src目录下新建store文件夹,再在store文件夹下新建index.js文件,在index.js文件中引入Vuex,然后将它挂载在项目main.js上,供全局调用。

安装:npm install vuex --save

// index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// main.js
import Vue from 'vue'
import store from './store'

new Vue({
  store, //全局新建store实例
  render: h => h(App)
}).$mount('#app')

Vuex属性介绍

创建store,store就相当于this,有且只有一个,vuex这个插件其实就是一个store对象,vue可以通过this.$store来调用vuex的属性与数值,这是vuex的核心。

// index.js
const store = new Vuex.Store({...}) //内部为其五大属性

尤其可见,store为新建的Vuex实例,接下来就来讲他内部的五大属性:

  1. state:Vuex定义数据并存放
  2. getters:相当于state的计算属性,从state派生出一些状态
  3. mutations:更改store中的状态唯一方法就是提交mutation,它是同步的(如果需要异步可使用actions来调用commit(’mutation对应方法名’)这种方法来搭配使用),每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler),回调函数就是我们更改的数据,例如:state,state便作为第一个参数,可传载荷作为第二个参数。
  4. actions:Action 类似于 mutation,不同在于:
    action 提交的是 mutation,而不是直接变更状态;
    action可以进行任何异步操作,mutation不可以;
  5. modules:模块化管理,有多个state可以通过模块化import到index.js的module属性中,可直接进行调用。参考vue的组件化思想。

注意:store 中存储的状态是响应式的,当组件从store中读取状态时,如果store中的状态发生了改变,那么相应的组件也会得到更新;

Vuex五大属性使用

首先看一下完整的store实例结构

// index.js
import Vue from 'vue'
import Vuex from 'vuex'
import timepiece from './lw/timepiece.js'

Vue.use(Vuex)
const store = new Vuex.Store({
	state: { ... },//定义状态,存放状态
	mutations: { ... },// 事件存放位置,更改数据状态,同步操作
	actions: { ... },// 修改mutations事件,异步操作
	getters: { ... },// state计算属性
	// 引入实例模块
	modules: { timepiece } //结构与这里的store实例一模一样,只是把逻辑都写到timepiece实例里面
})
export default store; //暴露,供外部访问

state

Vuex 使用单一状态树,它的一个对象就对应全部应用层级状态,即五大属性。所以每个对象也会享受一个store实例。

如何在Vue中获得Vuex状态

Vuex是响应式状态存储的,每当state对应发生变化,就会重新响应层级状态。如下:

// 创建一个 Counter 组件
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count  // count为state创建的状态
    }
  }
}

每当store.state.count发生改变,都会重新求取计算属性,并且触发更新相关联的 DOM。

前面已经讲到将store实例挂载在main上,这样的话就不需要在组件中频繁地导入

挂载之后组件调用方法:

  1. this.$store
  2. mapState 辅助函数
    当我们要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。mapState 辅助函数就来帮助生成计算函数:
// 在单独构建的版本中辅助函数为 Vuex.mapState
import { mapState } from 'vuex'

export default {
  // ...
  computed: mapState({
    // 箭头函数可使代码更简练
    count: state => state.count,

    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',

    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })
}

当映射的计算属性的名称与 state 的子节点名称相同时,可以给 mapState 传一个字符串数组

computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'  // count为state创建的状态
])

mapState 函数返回的是一个对象,为了将它里面的计算属性与组件本身的局部计算属性组合起来,需要用到对象展开运算符:

import { mapState } from 'vuex'
export default{
	computed: {
		...mapState(['count']), // count为state创建的状态
	}
}

Getter

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。它可以帮助我们去从 store 的 state中派生出一些状态,例如:对列表进行过滤并计数:

computed: {
  doneTodosCount () {  //state中的某个状态
    return this.$store.state.todos.filter(todo => todo.done).length //被返回的处理后的值
  }
}

组件访问方法:

  1. 通过属性访问:
    Getter暴露 store.getters 对象,直接用它去访问
store.getters.doneTodos // doneTodos为getters中的状态

前面提到可以携带第二个参数,那么我们把其它getters作为第二个参数,也是可以的:

getters: {  // getters区间
  doneTodos:(state) => { return ... }, //状态doneTodos
  doneTodosCount: (state, getters) => {  //getters作为第二个参数
    return getters.doneTodos.length  //doneTodosCount中可以拿到getters中的其它状态 doneTodos
  }
}

Vue组件中访问:

computed:{
	doneTodosCount(){
		return this.$store.getters.doneTodosCount
	}
}

注意,getter 在通过属性访问时是作为 Vue 的响应式系统的一部分缓存其中的

  1. 通过方法访问
store.getters.getTodoById(2) // -> { id: 2, text: '...', done: false }
  1. mapGetters 辅助函数
    mapGetters与mapState用法相同
import { mapGetters } from 'vuex'
export default{
	computed: {
		...mapGetters(['doneTodosCount']) //doneTodosCount为getters中的状态
		// 或者
		...mapGetters({doneCount: 'doneTodosCount'})  //等同于上面,结果重复赋值到doneCount上
	}
}

Mutations

mutations是直接操作state中数据的方法的集合,例如对数据的增、删、改等等

const store = new Vuex.Store({
	state: {
		count:1,
	},
	mutations:{
		// 定义一个事件名 increment
		increment(state) {  //state指向state里面的所有
			// 操作逻辑
			state.count++
		}
	}
})

关于mutations方法调用,假设事件名为 increment

store.commit('increment')  //actions内部就是这样调用

mutations方法调用的时候可以提交载荷(payload),就是额外传输一个参数,参数可以为数组、字符串、对象等,称为对象方式分发
载荷—int类型:

mutations: {
	increment(state,n) {  //这是接收
		state.count += n
	}
}
store.commit('increment',10)  //这是传值

载荷 / 对象分发:

mutations: {
	increment(state,payload) {  //这是接收
		state.count += payload.amount
	}
}
store.commit('increment',{amount: 10})  //这是传值---载荷
// 或者
store.commit({
	type:'increment',
	amount: 10   //这是传值---对象分发
})

Mutations一样可以调用mapMutations辅助函数的方法简写

import { mapState, mapGetters, mapMutations } from 'vuex'

export default {
	computed: {
		...mapState(['...']), //括号中...为事件名
		或者
		...mapState({ count: state=>state.count }), 
		...mapGetters(['...']) //括号中...为事件名
	},
	methods: {
		...mapMutations([ '...' ])  //括号中...为事件名
	}
}

Action

综上可知,action与mutation相似,但action包含任何异步操作,并且不能直接修改state,所以只能通过调用mutations的事件名来修改

const store = new Vuex.Store({
	state: {
		count: 0
	},
	mutations: {
		increment(state) {
			state.count++
		}
	},
	actions: {
		increment(context) {  //context就是当前的vuex实例对象;它拥有实例的所有方法
			context.commit('increment')
		}
		或者
		increment({commit}) { commit('increment') }
	}
})

关于actions方法调用,假设事件名为 increment

store.dispatch('increment')

actions 同样支持载荷方式和对象方法分发:
载荷 / 对象分发:

actions: {
	incrementAsync({ commit }) {
		setTimeout(()=> {
			commit('increment')
		},1000)  //这就是mutations与actions的区别---异步
	}
}
// 载荷
store.dispatch('incrementAsync', { amout: 10 })

// 对象分发
store.dispatch({
	type:'incrementAsync',
	amout: 10
})

actions一样可以调用mapActions辅助函数的方法简写

import { mapActions } from 'vuex'
export default {
	methods: {
		...mapActions(['...']),  // 括号中的...为方法名
		...mapActions({ add:'...' })  // this.$store.dispatch('...')
	}
}

组合 actions
有时项目需要在actions内部A调用B,如何解决这一问题呢?首先,store.dispatch处理函数返回的Promise并返回Promise

actions:{
	actionA({commit}) {
		return new Promise((resolve,reject) => {
			setTimeout(() => {
				commit('someMutation')
				resolve()
			},1000)
		})
	}
}
// 另一个actions
actions: {
	actionA({commit}) { ... }, //如上
	actionB({ dispatch,commit }) {
		return dispatch('actionA').then(() => {
			commit('someOtherMutation')
		})
	}
}
store.dispatch('actionA').then(() => { ... }) //另外组件中可以这样去操作

async / await 组合 actions

// 假设 getData() 和 getOtherData() 返回的是 Promise
actions: {
  async actionA({ commit }) {
    commit('gotData', await getData())
  },
  async actionB({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

一个 store.dispatch 在不同模块中可以触发多个 action 函数。在这种情况下,只有当所有触发函数完成后,返回的 Promise 才会执行。

Modules

模块化管理,用法如下:

// 新建timepiece.js文件,命名随意
const timepiece = {
	state: { count: 0 },
	mutations: { ... },
	actions: { ... },
	getters: { ... },
}
export default timepiece
// index.js
import timepiece from './lw/timepiece.js' //路径
const store = new Vuex.Store({
	state: { ... },
	mutations: { ... },
	actions: { ... },
	getters: { ... },
	modules: { timepiece }  // 引进
})

假设组件要调用
state

this.$store.state.timepiece.count

Getters

this.$store.getters.count

Mutations

this.$store.commit('start')

Action

this.$store.dispatch('start')

本文是针对vuex官网总结的一些个人心得。至此,总结结束,希望对大家有帮助,后期会根据vuex做一个或多个项目作为练习,以巩固知识。

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值