Vuex 状态管理器

Vuex 的核心概念

在 Vuex 中有五个核心概念,它们分别是 StateGettersMutationsActionsModules

接下来我们会通过示例为大家介绍 Vuex 的核心概念。

在介绍核心概念之前我们先在项目中安装 Vuex。

在项目中安装 Vuex

首先,打开我们的线上环境,使用下面命令获取 Vue 项目文件。

wget https://labfile.oss.aliyuncs.com/courses/10532/first-vuex.zip && unzip first-vuex.zip && rm first-vuex.zip
cd first-vuex
npm install

然后,使用以下命令快速将 Vuex 安装到我们的项目中:

npm install vuex@3.6.2
因为 Vue 2 中只能使用 vuex 3 所有这里我们下载指定版本的 vuex。

安装成功后我们会在 package.json 中找到它的相关信息:

核心概念之:state(用来存储和初始化状态)

首先,在 main.js 文件中写入以下代码:

import Vue from"vue";
import App from"./App.vue";
import Vuex from"vuex"; // 导入 Vuex

Vue.use(Vuex); // 使用 Vuex,让 Vuex 可以访问到 Vue
Vue.config.productionTip = false;

// 创建 Store 实例const store = new Vuex.Store({
  state: {
    count: 0, // 计数器的初始值
  },
});

new Vue({
  store, // 注入 Storerender: (h) => h(App),
}).$mount("#app");

有同学可能会问:为啥不叫 vuex 而是 store 呢?🤔

这是因为,Vuex 应用的核心就是 store(仓库)。它是一个用于存储组件共享状态(state)的容器,就像一个小型的数据仓库。它所有的功能和操作都是用于处理这个仓库中的状态而存在的,所以我们在创建 Vuex 配置的时候都是以 store 命名。

接下来,我们在 App.vue 中将计数器的状态展示出来,在文件中写入以下代码。

<template><divid="app">{{count}}</div></template><script>exportdefault {
    name: "App",
    // 通过计算属性来访问 countcomputed: {
      count() {
        returnthis.$store.state.count;
      },
    },
  };
</script>

来这里我们就可以在页面上访问到 count 的数据了,当前页面会显示 0。

接下来,我们要实现点击按钮计数的功能,每点一次按钮数据 +1。

核心概念之:mutations(唯一可以修改state值的方法,同步,必须用commit调用)

App.vue 文件中定义一个按钮,新增代码如下:

<!--绑定一个点击事件,用 increment 来执行 count++ 的逻辑-->
<button @click="$store.commit('increment')">++</button>

我们在 main.js 文件中增加 mutations,代码如下:

const store = new Vuex.Store({
  // 此处省略 ...mutations: {
    increment(state) {
      state.count++; // 执行 count++ 的操作
    },
  },
});

计数器的功能就实现啦~ 🎉 效果如下:

到此我们已经实现了一个最简单的 Vuex 状态管理,从上面的使用我们可以看出 state 就是用来存储和初始化状态。

通过上面简单的示例,我们知道了 Vuex 主要是用来存储并管理组件共享状态的。

核心概念之:actions(异步调用mutations方法,必须用dispatch调用)

有时候我们需要向后台发出一些异步请求,我们不能直接在 mutations 里进行操作,这时就可以在 actions 中定义一些异步操作。

下面我们来模拟一下异步操作,在页面上新增一个按钮,触发 count-- 的操作。在 App.vue 中新增以下代码:

<button @click="$store.dispatch('decrement')">--</button>
注意哦!!! Actions 是通过 store.dispatch 方法来触发 actions 更新 state 状态。

main.js 文件中新增以下内容。

const store = new Vuex.Store({
  mutations: {
    decrement(state) {
      state.count--;
    },
  },
  actions: {
    decrement({ commit }) {
      setTimeout(() => {
        // 通过 commit 交给 mutations 去处理
        commit("decrement");
      }, 500);
    },
  },
});

到这里我们 count-- 的功能也实现了,效果如下:

actions 与 mutations 的区别。

actions 类似于 mutations,不同的是:

  • actions 中的更新函数最终仍是通过调用 mutations 中的函数来更新状态的,不能通过它直接变更状态。

  • mutations 不同,actions 中可以包含任意异步操作。

关于 mutationsactions 等的用法还有其它形式,这些在官网上都有详细的 API,大家可以根据官网 API 对它们进行更多更深入的了解,这里就不再一一细说了。

核心概念之:getters(唯一取值的方法)

getters 可以帮助我们缓存数据。

我们增加一个每次计数增加两倍的功能,在 main.js 中新增以下代码:

getters: {
    doubleCount(state) {
      return state.count * 2
    }
}

然后在页面上获取数据,在 App 文件中新增以下代码:

{{$store.getters.doubleCount}}

这样,当点击 ++ 按钮时,计数会以乘 2 的形式增加。效果如下:

Vuex 规则

在实际开发中 Vuex 并不会限制我们的代码结构。但是,它规定了一些需要遵守的规则:

  1. 应用层级的状态应该集中到单个 store 对象中。

  1. 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。

  1. 异步逻辑都应该封装到 action 里面。

只要你遵守以上规则,如何组织代码随你便。

不过随着业务的增多,我们可能会面临这样一个问题:由于 statemutationsgettersactions 存储的内容越来越多,会导致 store 文件及其庞大,开发和维护起来变得困难。没关系,学习过 ES6+ 的同学都知道模块化的概念,这里我们可以将它们作为单独的文件从 store 中分割出去。这样做对于大型应用开发来说在合适不过。😊

我们可以将 store 分割为如下所示的结构:

└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── state.js          # 根级别的 state
    ├── getters.js        # 根级别的 getters
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation

核心概念之:Module

不过,前面对于 store/index.js 的分割并不是最小单元,我们在开发中仍然面临类似的问题。

有同学开始疑惑了:还有什么问题?

这要从 Vuex 的第一条规则说起。

来回顾下它的第一条规则:应用层级的状态应该集中到单个 store 对象中。

这句话也就意味着,一个应用的所有状态都会集中到一个比较大的对象中,当我们的应用变得非常复杂时,store 对象就有可能变得相当臃肿,其形式参考下图:

从图中可以看到,所有业务模块的 statemutations 等都存储在一个对象中,这使得我们的代码又一次变得复杂了。😫

这并不能仅靠将 statemutations 等对象从 store/index.js 文件中分割出来就能解决。

理想状态应该是这样的,我们可以按照业务逻辑划分为单个的 store,里面包含该模块中的 statemutations 等。就像下图那样:

这样怎么实现呢?🤔

实际上 Vuex 已经为我们考虑到了,并给出了解决方案,那就是 Vuex 的另一个核心概念——Modules

如前面所说,由于使用单一的状态树,应用的所有状态会集中到一个比较大的对象中。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

为了解决这个问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割:

具体语法如下:

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的状态
store.state.b // -> moduleB 的状态

分割后的项目结构如下:

└── store
    ├── index.js          # 我们组装模块并导出 store 的地方
    ├── state.js          # 根级别的 state
    ├── getters.js        # 根级别的 getters
    ├── actions.js        # 根级别的 action
    ├── mutations.js      # 根级别的 mutation
    └── modules
        ├── cart.js       # 购物车模块
        └── products.js   # 产品模块

至此,前面的问题便迎刃而解了。🎉

总结

本节实验我们学习了 Vuex 的安装与配置,并通过示例了解到它的几个核心概念 State、Getter、Mutation、Action 以及 Module 的作用及基本使用方式。

通过示例可以体会到 Vuex 状态管理器在简化组件间数据传递方面为开发带来的便利,不过状态管理器也不是所有组件传参的替代方案,大家要在使用前先对实际情况进行分析,把它用在必要的地方。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冥王丁B

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值