在现代前端开发中,组件化已成为一种广泛采用的开发模式。然而,当多个组件需要访问相同的数据时,如何进行高效的数据共享成为一个挑战。为了解决这个问题,Vuex 应运而生。Vuex 是一种实现组件全局状态管理的机制,能够方便地实现组件之间数据的共享。本文将介绍 Vuex 的基本概念、集中管理共享数据的功能及其优势,以及何时适合将数据存储到Vuex中。读者将对Vuex有更清晰的认识,并能够更好地利用它来管理和共享数据。

1.认识Vuex

Vuex 是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。

用 Vuex统一管理状态的好处:

      1.能够在 Vuex 中集中管理共享的数据,易于开发和后期维护。
      2.能够高效地实现组件之间的数据共享,提高开发效率。
      3.存储在 Vuex 中的数据都是响应式的,能够实时保持数据与页面的同步。

什么样的数据适合存储到Vuex中:
一般情况下,只有组件之间共享的数据,才有必要存储到 Vuex 中;对于组件中的私有数据,依旧存储在组件自身的data中即可。

2.Vuex的引入

(1)安装vue依赖包

npm i vuex@3.2.0 --save
本文所采用的是Vue2版本,所以这里使用3.2.0版本Vuex,其他版本请参考:官方文档

(2)创建store对象

在store/index.js中导入Vuex包并创建store对象:

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store=new Vuex.Store({
    //state中存放的就是全局共享的数据
    state:{count:0}
})
export default store

(3)挂载store

在main.js中导入store对象并挂载到vue实例中:

import store from './store'
new Vue({
    render: h => h(App),
    store
}).$mount('#app')

3.Vuex的基本使用

(1)State

State提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储
组件访问state中数据的第一种方式:
this.$store.state.全局数据名称
组件访问state中数据的第二种方式:
1.从vuex中按需导入mapState函数:import {mapState} from 'vuex'
2.将全局数据,映射为当前组件的计算属性:computed:{...mapState(['count'])}
3.直接使用count即可

<template>
	<div>
		<div>{{this.$store.state.count}}</div>
		<div>{{count}}</div>
	</div>
</template>

<script>
	import {mapState} from 'vuex'
	export default {
		computed: {
			...mapState(['count'])
		}
	}
</script>

(2)Mutation

Mutation用于变更Store中的数据
1.只能用mutation变更Store数据,不可以直接操作Store中的数据
2.通过这种方式虽然操作起来稍微繁琐一些,但是可以集中监控所有数据的变化

//定义Mutation
const store = new Vuex.Store({
	state: {count: 0},
	mutations: {
		add(state) {
			//变更状态
			state.count++
		},
		//可以在触发mutations时传递参数
		addN(state, step) {
			state.count += step
		}
	}
})

同样,触发mutations也有两种方式:

//触发mutations的第一种方式
//commit 的作用 就是调用某个mutation函数
this.$store.commit('add')
this.$store.commit('addN',3)

//触发mutations的第二种方式
//从vuex中按需导入mapMutatuons函数
import {mapMutatuons} from 'vuex'
//将指定的mutations函数,映射为当前组件的methods函数
methods:{
	...mapMutations(['add','addN'])
}

注意:
1.不建议直接在组件中操作store中的数据,这样写是不对的:this.$store.state.count++
2.不要在mutations函数中,执行异步操作

(3)Action

Action用于处理异步任务
如果通过异步操作变更数据,必须通过Actioin,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方法变更数据

//定义Action
const store=new Vuex.Store({
	state:{count:0},
	mutations:{
		add(state){
			state.count++
		},
                addN(state, step) {
			state.count += step
		}
	},
	actions:{
		addAsync(context){
			setTimeout(()=>{
				//在actions中 不能直接修改state中的数据
				//必须通过 context.commit()触发某个mutation
				context.commit('add')
			},2000)
		},
                addAsyncN(context,step){
			setTimeout(()=>{
				//在actions中 不能直接修改state中的数据
				//必须通过 context.commit()触发某个mutation
				context.commit('addN',step)
			},2000)
		}
	}
})

同理,触发action的两种方式:

//触发Action的第一种方式
//这里的dispatch函数 专门用来触发action
this.$store.dispatch('addAsync')	
this.$store.dispatch('addAsyncN',3)

//触发actions的第二种方式
//从vuex中按需导入mapActions函数
import {mapActions} from 'vuex'	
//将指定的actions函数,映射为当前组件的methods函数
methods:{
	...mapActions(['addAsync','addAsyncN'])
}

(4)Getters

Getter用于对Store中的数据进行加工处理形成新的数据
1.Getter可以对Store中已有的数据加工处理之后形成新的数据,类似Vue的计算属性
2.Store中数据发生变化,Getter的数据也会跟着变化

const store=new Vuex.Store({
	state:{count:0},
	getters:{
		showNum(state){
			return '当前最新的数量是['+state.count+']'
		}
	}
})

同理,使用getters的两种方式:

//使用getters的第一种方式:
this.$store.getters.showNum

//使用getters的第二种方式:
import {mapGetters} from 'vuex'
computed:{
	...mapGetters(['showNum'])
}

(5)Modules

Module是store分割的模块,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。
这里将上述的store单独抽离到app.js文件中:

// store/app.js 文件
const state = {
	count: 0 // 需要管理的状态数据
}
const mutations = {
	addN(state, step) {
		state.count += step
	}
}
const actions = {
	addAsyncN(context, step) {
		setTimeout(() => {
			context.commit('addN', step)
		}, 2000)
	}
}
const getters = {
	showNum(state) {
		return '当前最新的数量是[' + state.count + ']'
	}
}

export default {
	namespaced: true, // 为了解决不同模块命名冲突的问题
	state,
	mutations,
	getters,
	actions
}

此时,index.js代码如下:

// store/index.js 文件
import Vue from 'vue'
import Vuex from 'vuex'
import app from './app.js'
Vue.use(Vuex)

const store = new Vuex.Store({
	state: {},
	mutations: {},
	actions: {},
	getters: {},
	modules: { // 子vuex状态模块注册
		namespaced: true, 
		app,
	}
})
export default store

在vue文件中使用state、mutation、action、getters的方法如下:

// 使用state
this.$store.state.app.count
// 使用mutation
this.$store.commit('app/addN', 3)
// 使用action
this.$store.dispatch('app/addAsyncN', 3)
// 使用getters
import {mapGetters} from 'vuex'
computed: {
	...mapGetters({
	    showNum: 'app/showNum'
	})
}

注意:这里在使用他们时都需要指明所在的命名空间。state、mutation、action的两种使用方法仍然有效,但getters只能通过mapGetters函数使用。