【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 官方提供并维护的,可以选择用或不用,取 决于实际情况

相关推荐
peijiping17 分钟前
Agent 工具执行:并行(parallel_tool_calls)和后台(run_in_background)到底有什么区别? (学习笔记)
笔记·学习·ai agent·claude code
Oll Correct19 分钟前
Adobe illustrator 案例四:吃豆人 (Pac-Man)图标绘制
笔记·ui·adobe·illustrator
LuminousCPP28 分钟前
单链表专题(四)-刷题复盘篇-LeetCode 138 随机链表复制|原地拷贝法突破复杂指针操作
数据结构·笔记·算法·leetcode·链表
萌新小白YXY38 分钟前
SAE J1587/SAE J1708 协议笔记
笔记·单片机·嵌入式硬件
IT古董1 小时前
【MES学习笔记系列】MES 推荐书籍与资源
笔记·学习
一米阳光86611 小时前
软考(中级)软件设计师核心笔记(9)算法——时间复杂度与空间复杂度、查找算法、排序算法
笔记·算法·职场发展·软考·软件设计师·中级职称
米饭不加菜1 小时前
常用基本求导公式与法则(超详细推导版——上)
经验分享·笔记
唐诺2 小时前
flutter StreamController 完全使用指南
flutter·stream
青山是哪个青山10 小时前
LangChain 学习笔记(四):Message 与提示词模板
笔记·学习·langchain
java1234_小锋13 小时前
Vue3专题 - 组件基础
vue.js·vite