Vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态(数据)管理模式。在Vue中实现集中式状态管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。
在vue开发中,每个组件都有自己的独立的数据,整个项目中的所有组件可以通过bus总线进行传值,但是如果出现组件之间需要共用同一组数据时,数据管理就会非常麻烦。vuex是vue的状态(数据)管理工具,它采取了一种集中管理数据的思想,将整个项目中所有的公共数据放在一个统一的仓库中,然后任何组件都可以从这个仓库中读取数据,也可以通过仓库提供的方法修改数据。
什么情况下我应该使用 Vuex?
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式 (opens new window)就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
使用场景总结为:
- 多个组件依赖于同—状态
- 来自不同组件的行为需要变更同—状态
Vuex原理
使用Vuex的步骤
- Vue 3 匹配的 Vuex 4:npm install vuex@4 --save
- Vue 2 匹配的 Vuex 3:npm install vuex@3 --save
安装
安装vuex3的版本需要使用 vuex@3
npm install vuex@3 --save
安装vuex4的版本需要使用 vuex@4
npm install vuex@ --save
导入并use使用
在一个模块化的打包系统中,您必须显式地通过 Vue.use()
来安装 Vuex:
在src目录中添加store文件夹,在store文件夹中创建index.js,在index.js中安装Vuex,创建store实例
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
新建Store 仓库对象
// store/index.js
timer = null;
const store = new Vuex.Store({
// 在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到
strict: process.env.NODE_ENV !== 'production',
// 设置仓库的初始状态:初始数据
state:{
count: 1,
base: 10,
message: 'Hello Vuex!',
},
// getter 就像计算属性一样,只有当它依赖的值发生了改变才会被重新计算。
// 1、一般是做数据处理:排序、保留小数点等
// 2、不需要直接改变getters中的属性,getters中所依赖的数据发生变化时,getters中的属性会自动计算
getters:{
bigCount: state => state.count * 2,
baseCount: state => state.count * state.base,
}
// mutation: 定义一些函数,作用:改变state中数据
// 1、改变state中数据唯一的方法就是提交mutation
// 2、在mutation中的所有操作都必须是同步的
mutations:{
INCREASE_COUNT(state, value) {
state.count += value;
},
DECREASE_COUNT(state, value) {
state.count -= value;
},
SET_BASE(state, value) {
state.base = value;
},
}
// action: 类似mutation,也是定义一些函数,和mutation有些不一样
// 1、action中不能直接改变state,需要在action中提交mutation
// 2、action中可以包含异步操作:ajax请求等
actions:{
setCount(context, data) {
if (data.type == 0) {
context.commit('INCREASE_COUNT', data.value);
} else {
context.commit('DECREASE_COUNT', data.value);
}
},
// 不停的点击按钮时候,让count的值每隔一秒种增加或者减少1
setCountWaitOneSecond({ dispatch }, data) {
if (timer) return;
timer = setTimeout(() => {
dispatch('setCount', data); //在一个action中分发另外一个action
timer = null;
}, 1000);
},
setCountWidthBase({ dispatch, state }, data) {
dispatch('setCount', { type: data.type, value: state.base });
},
}
});
export default sotre;
在仓库store实例中添加数据,vuex的状态,就是数据
- state 仓库中数据存储位置,
- getters 仓库数据的处理,类似于组件的computed
- mutations 同步方式改变仓库的数据,通过commit提交mutation来改变state中的数据
- actions 异步方式修改仓库的数据,通过dispatch触发action的异步操作来修改state,在action中依旧需要提交mutation才能修改state
store的使用有两种方式:在模块中和在组件中
在模块中使用store
在JS模块中导入store实例
import store from './store'
store.state //获取仓库的状态
store.state.count //获取仓库的数据
store.commit('INCREASE_COUNT', 1); //提交mutation
在组件中使用store
为了在 Vue 组件中访问 this.$store
,你需要为 Vue 实例提供创建好的 store。Vuex 提供了一个从根组件向所有子组件,以 store
选项的方式“注入”该 store 的机制:
new Vue({
// 在根组件挂载store实例之后,再任何一个子组件中都能通过 this.$store 访问 store 实例
store,//挂载store
render: h => h(App),
}).$mount('#app')
2.2 在任意一个子组件中
created(){
this.$store //获取store实例
this.$store.state //获取仓库的状态
this.$store.state.count //获取state的数据
this.$store.commit('INCREASE_COUNT', 1); //提交mutation
}
Vuex 和单纯的全局对象有以下两点不同:
1、Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
2、你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
把store的数据变为组件的数据
访问state
访问state,一般我们把state中的数据作为组件的计算属性来属性
方式一:使用 this.$store.state 获取状态
computed:{
count(){
return this.$store.state.count;
}
}
方式二:使用 mapState 辅助函数
import {mapState} from 'vuex
computed: {
// 借助mapState生成计算属性:count、message(对象写法)--- 对象写法可以对属性进行重命名
...mapState({count:'count', message:'message'}),
// 借助mapState生成计算属性:count、message(数组写法)--- 需要和state中的属性名保持一致
...mapState(['count', 'message']),
}
访问getters
访问getters,一般我们把getters中的数据作为组件的计算属性来属性
方式一:使用 this.$store.getters 获取状态
computed:{
count(){
return this.$store.getters.bigCount;
}
}
方式二:使用 mapGetters 辅助函数
import {mapGetters} from 'vuex
computed: {
// 借助mapGetters生成计算属性:bigCount(对象写法)
...mapGetters({bigCount:'bigCount
// 借助mapGetters生成计算属性:bigCount(数组写法)
...mapGetters(['bigCount']),
}
提交mutation
方式一:直接使用 this.$store.commit() 提交
this.$store.commit('INCREASE_COUNT', 1);
方式二:使用 mapMutations 辅助函数
import { mapMutations } from 'vuex';
methods:{
increase1() {
// this.$store.commit('INCREASE_COUNT', 1);
this.INCREASE_COUNT(1);
},
// 借助mapMutation生成函数:setCount(对象写法)
...mapMutations({INCREASE_COUNT:'INCREASE_COUNT'}),
// 借助mapMutation生成函数:SET_COUNT(数组写法)
...mapMutations(['INCREASE_COUNT']),//把SET_COUNT映射为组件自己的函数
}
分发action
方式一:直接使用 this.$store.dispatch()
this.$store.dispatch('setCount', { type: 0, value: 2 });
方式二:使用 mapActions 辅助函数
import { mapActions } from 'vuex';
methods:{
increase() {
// this.$store.dispatch('setCount', { type: 0, value: 2 });
this.setCount({ type: 0, value: 2 });
},
// 借助mapActions生成函数:setCount(对象写法)
...mapActions({setCount:'setCount'}),
// 借助mapActions生成函数:setCount(数组写法)
...mapActions(['setCount']),
}