用最简的方式学Vuex,你学会了吗?

开发 前端
Vuex是一个专为Vue.js应用程序开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化,每一个Vuex应用的核心是store(仓库)。

一、基础

Vuex是一个专为Vue.js应用程序开发的状态管理模式,采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化,每一个Vuex应用的核心是store(仓库)。为了使用Vuex,首先需要安装该包,执行如下命令完成该安装过程。

npm install vuex@next --save

二、核心概念

Vuex中核心概念主要有五个:State、Getters、Mutations、Actions、Modules,每一部分都有自己的功用,下面先来看一段简单的代码,该代码中涉及到了这些核心概念,然后在该代码的基础上进一步理解。

// index.js文件
import {createStore} from "vuex";

import {moduleA} from "./module/moduleA";

export const store = createStore({
// Vuex允许将store分割成模块(module),每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块
// 访问moduleA的状态:store.state.moduleA
modules: {
moduleA
}
});

// module/moduleA.js文件
// 对于模块内部的mutation和getter,接收的第一个参数是模块的局部状态对象
// 对于模块内部的action,局部状态通过context.state暴露出来,根节点状态则为context.rootState
// 对于模块内部的getter,根节点状态会作为第三个参数暴露出来

// 在带命名空间的模块内访问全局内容
// 如果希望使用全局state和getter,rootState和rootGetters会作为第三和第四个参数传入getter,也会通过context对象的属性传入action
// 若需要在全局命名空间内分发action或提交mutation,将{root: true}作为第三个参数传给dispatch或commit即可。

export const moduleA = {
// 默认情况下,模块内部的action、mutation和getter是注册在全局命名空间的,如果希望模块具有更高的封装度和复用性,可以通过添加namespaced:true的方式使其成为带命名空间的模块
namespaced: true,
state: {
testState1: 'xxxx',
testState2: {
a: 0,
b: 1
},
testState3: 0
},
// 有的时候需要从store中的state中派生出一些状态,此时可以将该部分抽象出一个函数供多处使用。
// Vuex允许在store中定义getter,像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当他的依赖值发生了改变才会被重新计算
getters: {
// getter接收state作为其第一个参数
testGetter1: state => {
return state.testState1 + state.testState3;
},
// getter可以接受其他getter作为第二个参数
testGetter2: (state, getters) => {
return getters.testGetter1.length;
}
},
// 更改Vuex的store中的状态的唯一方法是提交mutation,每个mutation都有一个字符串的事件类型和一个回调函数,该回调函数接收state作为第一个参数,提交的载荷作为第二个参数
// 以相应的type调用store.commit方法来触发相应的回调函数
// Mutation必须是同步函数
mutations: {
testMutation1(state) {
// 变更状态
state.testState3++;
},
// 第二个参数是载荷
testMutation2(state, payload) {
state.testState1 += payload.content;
}
},
// Action提交的是mutation,而不是直接变更状态
// Action可以包含任意异步操作
// Action函数接受一个与store实例具有相同方法和属性的context对象,因此可以调用context.commit提交一个mutation,或者通过context.state和context.getters来获取state和getters。
// Action通过store.dispatch方法触发
actions: {
testAction1(context) {
setTimeout(() => {
context.commit('testMutation1');
}, 1000);
},
testAction2({commit}, payload) {
setTimeout(() => {
commit({
type: 'testMutation2',
content: payload.content
});
}, 1000);
}
}
};

State

Vuex使用单一状态树保存所有数据,作为唯一数据来源。如上所示代码,其包含了testState1、testState2、testState3,在组件中如何获取这些数据呢?(Vue3.x语法)

<template>
<h1>组件三</h1>
<p>{{testState1}}</p>
<p>{{testState2}}</p>
<p>{{testState3}}</p>
</template>

<script setup>
import {computed} from 'vue';
import {useStore} from 'vuex';
// 通过useStore函数来访问store,与选项式API
const store = useStore();

// 从store中读取状态并显示到Vue组件中最简单的办法是将其绑定到计算属性上
// 如果想读取某一模块中的状态值,则需要store.state.模块名.状态名
const testState1 = computed(() => store.state.moduleA.testState1);
const testState2 = computed(() => store.state.moduleA.testState2.a + store.state.moduleA.testState2.b);
const testState3 = computed(() => store.state.moduleA.testState3);
</script>

<style lang="less"></style>

Getters

有的时候需要从store中的state中派生出一些状态,此时可以将该部分抽象出一个函数供多处使用。Vuex允许在store中定义getter,像计算属性一样,getter的返回值会根据它的依赖被缓存起来,且只有当他的依赖值发生了改变才会被重新计算。

<template>
<h1>组件三</h1>
// ……
<p>{{testGetter1}}</p>
<p>{{testGetter2}}</p>
</template>

<script setup>
import {computed} from 'vue';
import {useStore} from 'vuex';
// 通过useStore函数来访问store,与选项式API
const store = useStore();

// ……

// 在computed函数中访问getter
// 如果访问非模块中的getter,直接store.getters.名称
// 如果访问模块中的getter,通过store.getters['getter路径']
const testGetter1 = computed(() => store.getters['moduleA/testGetter1']);
const testGetter2 = computed(() => store.getters['moduleA/testGetter2']);

</script>

<style lang="less"></style>

Mutations

更改Vuex的store中的状态的唯一方法是提交mutation,每个mutation都有一个字符串的事件类型和一个回调函数,该回调函数接收state作为第一个参数,提交的载荷作为第二个参数。(注意:Mutation必须是同步函数)

<template>
<h1>组件三</h1>
// ……
<button @click="handleMutationsClick">改变</button>
</template>

<script setup>
// ……

// 与mutations相应的type调用store.commit方法来触发相应的回调函数
const handleMutationsClick = () => {
store.commit('moduleA/testMutation1');
store.commit('moduleA/testMutation2', {
content: 'content'
});
};

</script>

<style lang="less"></style>

Actions

Actions类似于mutation,但是仍然有一些不同点,一方面其提交的是mutation,而不是直接变更状态;另一方面Action可以包含任意异步操作。

<template>
<h1>组件三</h1>
// ……
<button @click="handleActionsClick">改变Action</button>
</template>

<script setup>
// ……

// Action函数接受一个与store实例具有相同方法和属性的context对象,因此可以调用context.commit提交一个mutation,或者通过context.state和context.getters来获取state和getters。
// Action通过store.dispatch方法触发
const handleActionsClick = () => {
store.dispatch('moduleA/testAction1');
store.dispatch('moduleA/testAction2', {
content: 'test'
});
};
</script>

<style lang="less"></style>

Modules

由于使用单一状态树,应用的所有状态都会集中到一个较大的对象,当应用变的复杂时store会变的很难维护,为了解决该问题,Vuex允许将store分割成模块(module),每个模块拥有自己的state、mutation、action、getter、甚至是嵌套子模块,具体使用可见第二节中开头部分的代码,其中包含了其常见的使用方式。

三、插件

3.1 插件基础

Vuex在实例化store的时候可以接受plugins选项,该选项可以添加一系列的插件,插件就可以帮助我们完成一系列的工作,节省人力和物力,下面我们自定义一个简单的插件并调用该插件。

// plugins/myPlugin.js
// 插件接收唯一的参数store
const myPlugin = store => {
// store上有一系列的方法,可以用在插件中https://next.vuex.vuejs.org/zh/api/#commit
// 注册一个动态模块用registerModule
// 替换store的根状态用replaceState
// 监听mutation的变化,该处理函数会在每个mutation完成后调用,接收mutation和经过mutation后的状态作为参数
store.subscribe((mutation, state) => {
console.log(mutation);
});
};

export default myPlugin;

// index.js
import {createStore} from "vuex";
import myPlugin from "./plugins/myPlugin";

export const store = createStore({
// ……
// 一个数组,包含应用在store上的插件方法,这些插件直接接收store作为唯一参数,可以监听mutation或者提交mutation
plugins: [myPlugin]
});

3.2 数据持久化插件

Vuex的状态存储并不能持久化,只要一刷新页面数据就丢失了,此时可引入vuex-persist插件来解决该问题,其会将状态保存至cookie或者localStorage中。

import {createStore} from "vuex";
import VuexPersistence from "vuex-persist";
import myPlugin from "./plugins/myPlugin";

// 利用该插件可实现对store数据的持久化
const vuexLocal = new VuexPersistence({
storage: window.localStorage
});

export const store = createStore({
// ……
// 一个数组,包含应用在store上的插件方法,这些插件直接接收store作为唯一参数,可以监听mutation或者提交mutation
plugins: [myPlugin, vuexLocal.plugin]
});

本文转载自微信公众号「前端点线面」,可以通过以下二维码关注。转载本文请联系前端点线面公众号。

责任编辑:武晓燕 来源: 前端点线面
相关推荐

2023-08-14 08:42:41

2022-07-08 09:27:48

CSSIFC模型

2024-02-04 00:00:00

Effect数据组件

2024-01-19 08:25:38

死锁Java通信

2023-01-10 08:43:15

定义DDD架构

2023-07-26 13:11:21

ChatGPT平台工具

2021-07-01 19:22:33

脚本Shell参数

2024-02-02 11:03:11

React数据Ref

2023-08-01 12:51:18

WebGPT机器学习模型

2024-01-02 12:05:26

Java并发编程

2024-05-28 10:08:05

2023-05-05 08:23:29

单测编程语言

2024-07-31 08:39:45

Git命令暂存区

2023-01-30 09:01:54

图表指南图形化

2024-08-06 09:47:57

2024-05-06 00:00:00

InnoDBView隔离

2023-10-10 11:04:11

Rust难点内存

2023-12-12 08:02:10

2024-05-29 07:47:30

SpringJava@Resource

2022-12-06 08:37:43

点赞
收藏

51CTO技术栈公众号