【Vue.js 入门笔记】 状态管理器Vuex

Vuex,用于管理分散在 Vue 各个组件中的数据。

每一个 Vuex 应用的核心都是一个 store(仓库),也可以理解它是一个"非凡的 全局对象"。

与普通的全局对象不同的是,基于 Vue 数据与视图绑定的特点,当 store 中 的状态发生变化时,与之绑定的视图也会被重新渲染。

这是一个单向的过程,因为 store 中的状态不允许被直接修改。改变 store 中的状态 的唯一途径就是显式地提交(commit)mutation,这可以让我们方便地跟踪每一个状态的 变化。(在大型复杂应用中,如果无法有效地跟踪到状态的变化,将会对理解和维护代 码带来极大的困扰。假如你能很好地理解使用 Vuex 进行状态管理的缘由,你就应该尽力 遵循"显式"的原则,即使你可以跳过这个过程。)

Vuex 中有 5 个重要的概念:State、Getter、Mutation、Action、Module。

1. State

state的用法如下:

复制代码
CreateStore({
	state:{
		count:1
	}
})

在组件中,可以直接使用$store.state.count(前提是store已经被注册到实例中),也可以先用mapState辅助函数将其映射下来。
代码如下:

import {mapState} from 'vuex'

export default {

computed:{

...mapState(['count']) // 是ES6中的对象展开运算符

}

}

2.Getter

Getter 维护由state派生的一些状态。这些状态随着State的变化而变化。

与计算属性一样,Getter 中的派生状态在被计算之后会被缓存起来,当重复调用时,如果被 依赖的状态没有变化,那么 Vuex 不会重新计算派生状态的值,而是直接采用缓存值。

Getter 的用法如下:

复制代码
createStore({
	state:{
		count:1
	},
	getters:{
	tenTimesCount(state){ // Vuex为其注入state对象
		return state.count*  10;
	}

})

在组件中。可以直接使用 $store.getters.tenTimesCount ,也可以先用mapGetters 辅助函数映射下来。代码如下

复制代码
import {mapGetters} from 'Vuex'
export default {
	computed :{
		... mapGetters(['tenTimesCount']); // ... 是ES6中的对象展开运算符
	}
}

3. Mutation

Mutation 提供修改State状态的方法

Mutation 的用法如下:

复制代码
newVuex.Store({ // 创建仓库
	state:{
		count:0
	},
	mutations:{
		addCount(state,num){
			state.count+= num ||1
		}
	}

})

在组件中,可以直接使用store.commit 来提交mutation,代码如下:

复制代码
methods:{
	addCount(){
		this.$store.commit('addCount') // store 被注入Vue实例中后可以使用this.$store
	}
}

也可以先用MapMutation 辅助函数现将其映射下来

复制代码
import {mapState.mapMutations} from 'vuex'
export default {
	computed:{
		...mapState(['count']) // ... 是es6中的对象展开运算符
	},
methods:{
		...mapMutations(['addCount']);
		...mapMutations({
			increaseCount:'addCount'
		})
	}
}

4. Action

Action类似Mutation两者的不同之处在于:

● Action 不能直接修改状态,只能通过提交 mutation 来修改。

● Action 可以包含异步操作。

Action的用法如下:

复制代码
createStore({
	state:{
	 	count:0
	},
	mutations:{
		addCount(state,num){
			state.count+= num ||1
		}
	},

actions:{
	// context具有和store实例相同的属性和方法
	//可以通过context获取state和getter属性里的值、或者提交mutation和分发其他的action
	addCountAsync(context,num){
		setInterval( function(){
			if(context.state.count<2000 ){
				context.commit('addCount',num || 100)
			}
		},num || 100)
	}

}

})

在组件中,可以直接使用store.dispatch来分发action。代码如下:

复制代码
methods:{
	addcountAsync(num){
		this.$store.dispatch('addAsync',num)
	}
}

或者使用mapActions辅助函数将其先映射下来。代码如下:

复制代码
import {mapState,mapActions} from 'vuex'
export default{
		computed:{
			..mapState(['count']) ; // ... 是ES6中的展开运算符
		},
		methods:{
		...mapActions(['addCountAsync']),
		...mapActions([{
				increaseCountAsync:'addCountAsync'
			}])
		}

}

5.Module

由于使用单一状态树,当项目的状态非常多时,store 对象就会变得十分臃肿。因 此,Vuex 允许我们将 store 分割成模块(Module),每个模块拥有独立的 State、Getter、 Mutation 和 Action,模块之中还可以嵌套模块,每一级都有着相同的结构。

Module 的用法如下:

复制代码
// 定义模块
const counter = {
  namespaced: true, // 定义为独立的命名空间
  
  state: {
    count: 0
  },
  
  getters: {
    // 在模块中,getter方法还有rootState、rootGetters参数可以获取根模块中的数据
    tenTimesCount(state, getters, rootState, rootGetters) {
      return state.count * 10;
    }
  },
  
  mutations: {
    addCount(state, num) {
      state.count += num || 1;
    }
  },
  
  actions: {
    // context具有和store实例相同的属性和方法
    // 可以通过context获取state和getters里的值,或者提交mutation,分发action
    // 在模块中,context还会具有rootState和rootGetters属性以获取根模块中的数据
    addCountAsync(context, num) {
      // 保存定时器ID以便后续可以清除
      const timerId = setInterval(() => {
        if (context.state.count < 2000) {
          context.commit('addCount', num || 100);
        } else {
          clearInterval(timerId); // 达到条件后停止
        }
      }, num || 100);
      
      // 返回定时器ID,可以在需要时清除
      return timerId;
    }
  }
};

// 创建仓库(假设这是Vuex 3.x的语法,Vuex 4.x用法略有不同)
import { createStore } from 'vuex'; // Vuex 4.x

// 或者对于Vuex 3.x:
// import Vue from 'vue';
// import Vuex from 'vuex';
// Vue.use(Vuex);

const store = createStore({
  modules: {
    counter // 注册模块
  }
});

export default store;

在组件中,模块的使用方式如下:

复制代码
import {mapState,mapGetters,mapMutations.mapActions} from 'Vuex'
export default {
	computed:{
		//辅助函数的第一个参数为模块的名称
		...mapState('counter',['count']);
		...mapGetters('counter',['tenTimesCount'])
	},
methods:{
	...mapMutatiuons('counter',['addCount']),
	...mapActions('counter',['addCountAsync'])
}

}

最后,结合 Vuex 用于管理分散在各个组件中的状态和追踪状态变更的初衷,简单总结了这些概念如下。作为一个状态管理器,首先要有保管状态的容器------State;为 了满足衍生数据和数据链的需求,从而有了 Getter;为了可以"显式地"修改状态,所 以需要 Mutation;为了可以"异步地"修改状态(满足 AJAX 等异步数据交互),所以 需要 Action;最后,如果应用有成百上千个状态,放在一起会显得十分庞杂,所以分模 块管理(Module)也是必不可少的。

Vuex 的用法如上,应该并不难理解。

Vuex 并不是 Vue 应用开发的必选项,在使用时,应先考虑项目的规模和特点,有选 择地进行取舍,盲目地选用只会带来更多的开发成本。

Vuex 为开发者提供了多种写法,不过并不推荐过多尝试和写法上的变换,毕竟 保持一致的风格也是高质量代码的一种表现,除非这种变化是一种进步。

本章所介绍的工具和插件均是由 Vue 官方提供并维护的,可以选择用或不用,取 决于实际情况

相关推荐
Jiaberrr2 小时前
小程序setData性能优化指南:避开坑点,让页面丝滑如飞
前端·javascript·vue.js·性能优化·小程序
方安乐2 小时前
react笔记之tanstack
前端·笔记·react.js
一起养小猫12 小时前
Flutter for OpenHarmony 进阶:体育计分系统与数据持久化深度解析
flutter·harmonyos
~牧马~12 小时前
【记录63】electron打包vue项目之踩坑
vue.js·electron·electron与node兼容
ujainu12 小时前
Flutter + OpenHarmony 游戏开发进阶:主菜单架构与历史最高分持久化
flutter·游戏·架构·openharmony
童话名剑13 小时前
序列模型与集束搜索(吴恩达深度学习笔记)
人工智能·笔记·深度学习·机器翻译·seq2seq·集束搜索·编码-解码模型
铅笔侠_小龙虾13 小时前
Flutter Demo
开发语言·javascript·flutter
2501_9445255413 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 账户详情页面
android·java·开发语言·前端·javascript·flutter
计算机学姐13 小时前
基于SpringBoot的电影点评交流平台【协同过滤推荐算法+数据可视化统计】
java·vue.js·spring boot·spring·信息可视化·echarts·推荐算法