vuex 基础回顾

89 阅读4分钟

概念

  • Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。一个状态自管理应用包含以下几个部分:
    • 状态(State),驱动应用的数据源;
    • 视图(View),以声明方式将状态映射到视图;
    • 操作(Actions),响应在视图上的用户输入导致的状态变化。
  • 以下是一个表示“单向数据流”理念的简单示意:

vuex.png

目的

1. 思考以下问题
  • 如果你的项目里有很多页面(组件/视图),页面之间存在多级的嵌套关系,此时,这些页面假如都需要共享一个状态的时候,此时就会产生以下两个问题:
    • 多个视图依赖同一个状态
    • 来自不同视图的行为需要变更同一个状态
2. 目前能想到的解决方案
  • 对于第一个问题,假如是多级嵌套关系,你可以使用父子组件传参进行解决,虽有些麻烦,但好在可以解决;对于兄弟组件或者关系更复杂组件之间,就很难办了,虽然可以通过各种各样的办法解决,可实在很不优雅,而且等项目做大了,代码就会变成屎山,实在令人心烦。
  • 对于第二个问题,你可以通过父子组件直接引用,或者通过事件来变更或者同步状态的多份拷贝,这种模式很脆弱,往往使得代码难以维护,而且同样会让代码变成屎山
3. vuex
  • 把各个组件都需要依赖的同一个状态抽取出来,在全局使用单例模式进行管理。
  • 在这种模式下,任何组件都可以直接访问到这个状态,或者当状态发生改变时,所有的组件都获得更新。
  • 这就是 Vuex 背后的基本思想,借鉴了 Flux、Redux。与其他模式不同的是,Vuex 是专门为 Vue 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新

安装

npm i vuex

名词概念

1. state
  • Vuex 使用单一状态树,也就是用一个对象就包含了全部的应用层级状态。
  • 至此它便作为一个 唯一数据源 (SSOT) 而存在。这也意味着,每个应用将仅仅包含一个 store 实例。
  • 单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照
2. getter

计算属性,可以理解成页面中的计算属性, 用法也一致

3. Mutation
  • 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
  • Vuex 中的 mutation 非常类似于事件:
    • 每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。
    • 这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
    • 注意:mutation 是同步的
4. Action
  • 类似于 mutation,但是它是异步的。不能直接修改 state
5. Module
  • 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
  • 为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分

代码演示

使用 vuex 在页面中实现 num++

1. 在 src 下创建 store 目录, 并添加 index.js 文件
// 从vuex 中引入 createStore
import { createStore } from "vuex";

// 创建一个新的 store 实例
const store = createStore({
    // state 是一个方法,存放状态的地方
    state() {
        // return的就是当前的状态
        return {
            num: 0,
        };
    },

    // 同步修改state
    mutations: {
        /**
         * 接收的第一个参数是当前的state
         * 第二个参数是传过来的参数
         */
        add(state, name) {
            console.log(name);
            state.num++;
        },
    },
    actions: {
        /**
         * 第一个参数是context 也就是当前上下文
         * 比如可以直接获取state、使用 commit 调用等
         *
         * 第二个参数是页面传过来的参数
         */
        asyncAdd(context, name) {
            console.log(name);
            /**
             * 使用 commit 调用 mutations 里面的方法改变数据
             * 第一个参数是方法名
             * 第二个是要传的参数
             */
            context.commit("add", name);
        },
    },
});

export default store;
2. 在入口文件引入, 并通过 use 挂载
import { createApp } from "vue";
import router from "./router";
import vuex from "./store";

createApp(LearnRouter)
    // 使用use 方法 把我们路由挂载到vue上
    .use(router)
    // 使用 use 把vuex挂载到实例上
    .use(vuex)
    .mount("#app");
3. 在页面中使用
<template>
    <div>
        {{ $store.state.num }}
        <button @click="add">+1</button>
        <button @click="asyncAdd">action</button>
    </div>
</template>
<script>
export default {
    methods: {
        add() {
            /**
             *  使用 this.$store.commit 方法调用 mutations 里面的方法
             *      第一个参数是方法名
             *      第二个参数是要传的参数
             */
            this.$store.commit("add", "张三");
        },

        asyncAdd() {
            // 使用 dispatch 调用 action里面的方法
            this.$store.dispatch("asyncAdd", "李四");
        },
    },
};
</script>