用最简的方式学Vuex

简介: 用最简的方式学Vuex

一、基础


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);
        }
    }
};
  1. 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>
  1. 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>
  1. 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>
  1. 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>
  1. 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]
});
相关文章
|
1天前
|
前端开发 JavaScript C++
【掰开揉碎】Django模板 vs 前端框架:选择合适的渲染方式
【掰开揉碎】Django模板 vs 前端框架:选择合适的渲染方式
|
9月前
|
前端开发 JavaScript
【React工作记录八十】 一步步教你用taro封装一个公司库的下拉组件
【React工作记录八十】 一步步教你用taro封装一个公司库的下拉组件
61 0
|
2天前
|
前端开发 容器
第十九章 案例TodoList之组件拆分
第十九章 案例TodoList之组件拆分
|
11月前
|
前端开发
前端学习笔记202304学习笔记第十二天-vue3.0-总结组件之间数据共享方案
前端学习笔记202304学习笔记第十二天-vue3.0-总结组件之间数据共享方案
40 0
|
11月前
|
前端开发
前端学习笔记202304学习笔记第十一天-vue3.0-了解vuex的概念和好处
前端学习笔记202304学习笔记第十一天-vue3.0-了解vuex的概念和好处
49 0
|
11月前
|
前端开发
前端学习笔记202304学习笔记第十一天-vue3.0-了解vuex的概念和好处
前端学习笔记202304学习笔记第十一天-vue3.0-了解vuex的概念和好处
43 0
|
设计模式 JavaScript 前端开发
面试官:Vue和React对于组建的更新粒度有什么区别?
我们都知道 Vue 对于响应式属性的更新,只会精确更新依赖收集的当前组件,而不会递归的去更新子组件,这也是它性能强大的原因之一。
|
JSON JavaScript API
【从零到一手撕脚手架 | 第二节】模块化封装 降低耦合度 封装 axios pinia router
前一节我们讲解了脚手架的基础项目搭建。接下来教大家将Vue技术栈常用的工具进行封装,让我们项目的代码更易维护。
280 0
【从零到一手撕脚手架 | 第二节】模块化封装  降低耦合度 封装 axios pinia router
|
JavaScript 前端开发 数据管理
大白话理解和初步使用vuex
大白话理解和初步使用vuex
110 0