全局状态管理插件 Vuex 介绍及使用

news2024/9/29 1:23:17

文章目录

      • Vuex 是什么
        • 简介
        • Vuex 如何存储数据
      • Vuex 核心概念
        • 单向数据流
        • State
        • Getter
        • Mutation
        • Action
        • Module
      • Vuex 使用实例
      • 总结

Vuex 是什么

简介

官方解释:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

笔者个人理解,一句即可以概括: Vuex 是用于管理 Vue 应用跨组件数据的工具。

跨组件数据指的是,在 A、B、C 组件都需要用到的数据,比如购物车的数量,在很多页面是需要用到的。

Vuex 如何存储数据

说起这个还真有很多同学对 Vuex 的存储概念比较模糊,那么下面我们来分析一下 Vuex 和 localStorage、sessionStorage 在存储上的区别。

  • Vuex

Vuex 存储在浏览器内存,它采用的是集中式存储管理应用的所有组件的状态,在不刷新网页的情况下,状态会一直保持,一旦刷新网页,所有状态都将会重制。

  • sessionStorage

sessionStorage 是一种会话型存储,用于保存同一窗口或标签页的数据,数据保存在浏览器本地,在关闭窗口或标签页之后将会删除这些数据,这就是会话型存储,就跟人于人说话一样,人走了对话就结束了。

  • localStorage

localStorage 是一种持久性存储,与 sessionStorage 的功能近乎相似,但是在数据的存储时长上有所区别。它可以让数据一直存在于浏览器本地,除非你主动的 clear 数据,或者重装浏览器。

很多同学会认为既然 localStorage 存储时效这么强大,为什么不能用它去代替 Vuex 管理应用的数据呢?当然,在某些场景下,数据存在 localStorage 是比较合适的,像一些不需要变化的数据。但是在 Vue 单页应用开发中,两个组件 A 和 B 共用一份数据,B 若是能响应 A 对数据的改动,这种情况下 localStorage 和 sessionStorage 就显得比较乏力,毕竟 Vuex 有一整套高度兼容 Vue.js 开发模式的结构。

Vuex 核心概念

单向数据流

什么是单向数据流呢?它指的是通过一定的规则去改变数据,数据触发视图的更新,通过视图中的方法去触发数据的更新,形成一个闭环。如下图所示:

img

但事与愿违,复杂应用里会遇到多个组件共享同状态,不同视图的行为变更同一个状态等等问题,这时单向数据流就会被破坏。

Vuex 的出现就是为了解决这类复杂场景应用,那么我们在看看一张官方提供的流程图:

img

绿色虚线框内被 Vuex 加持,Vue 组件通过 Dispatch 关键字触发 Actions,再通过 Commit 调用 Mutation 里的方法修改 State 数据,Vue 组件若是有依赖 Store 里的数据,那么便会触发 Vue
组件的 Render 重绘,这就又形成了一个闭环。

State

顾名思义,所有状态都将被存放在 State 中,类似 Vue 组件中的 data 属性,只不过 State 是面向整个应用,而 data 针对的是单个组件。在 Vue 入口页构造 Vue 实例的时候引入 store 之后,可以在组件中通过
this.$store.state 拿到。

Getter

它类似于 Vue 组件中的 computed 计算属性,计算一些需要二次改造的数据。举个例子,我在 Vue 组件中通过 this.$store.state 拿到 State 中的某个数据,但是我需要对这个数据过滤,一个 filter
方法就能拿到过滤后的数据,但是我在很多地方都要使用这个 filter 过滤条件,那么我不断的去复制粘贴(CV 大法),或者将这个 filter 方法抽离到公用函数再引入组件,两种方法都很鸡肋。Getter 为我们解决了这个难题,你可以在
store 中定义 getter 属性,state 数据可作为参数被传入,代码大致如下:

const store = new Vuex.Store({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false },
    ],
  },
  getters: {
    doneTodos: (state) => {
      return state.todos.filter((todo) => todo.done);
    },
  },
});

在 Vue 组件中便可以通过如下方式进行访问:

this.$store.getters.doneTodos; // [{ id: 1, text: '...', done: true }]

Getter 也可以接收其他的 getters 作为第二个参数:

getters: {
  // ...
  doneTodosCount: (state, getters) => {
    return getters.doneTodos.length;
  };
}
// 使用
store.getters.doneTodosCount; // -> 1

可以通过 mapGetter 将 store 中的 getter 属性映射到局部计算属性内:

import { mapGetters } from 'vuex';

export default {
  // ...
  computed: {
    // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ]),
  },
};

在 Vue 组件中便可以直接用 this.doneTodosCount 取到你想要的过滤后的数据。

Mutation

我们修改 State 状态,需要触发一些方法,这些方法就放在 mutations 属性中,mutations 属性中的方法接受 2 个参数,第一个参数是
state,内部包含所有状态值。第二个参数为提交载荷(Playload),也就是在外部通过 store.commit 方法触发 mutations 时额外带入的值。代码如下所示:

const store = new Vuex.Store({
  state: {
    count: 1,
  },
  mutations: {
    increment(state) {
      // 变更状态
      state.count++;
    },
  },
});

// 触发
store.commit('increment'); // 参数名称必须对应 mutations 的方法属性值。

//
const store = new Vuex.Store({
  state: {
    count: 1,
  },
  mutations: {
    increment(state, n) {
      state.count += n;
    },
  },
});

// 带载荷触发
store.commit('increment', 10);

Action

其实 Action 很好理解,它与 Mutation 类似,只不过 Action 是提交 mutation 而不是直接改变状态,并且 Action 被赋予异步的能力,也就是能在里面请求异步数据之后再触发状态的更新。

简单代码演示:

const store = new Vuex.Store({
  state: {
    count: 0,
  },
  mutations: {
    increment(state, data) {
      state.count += data.length;
    },
  },
  actions: {
    async increment(ctx) {
      const data = await getData();
      ctx.commit('increment', data);
    },
  },
});

// 分发 Action
store.dispatch('increment');

mapActions 帮我们更好的在页面中分发 Actions(在此之前需要在入口页注入 store):

import { mapActions } from 'vuex';

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`

      // `mapActions` 也支持载荷:
      'incrementBy', // 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`
    ]),
    ...mapActions({
      add: 'increment', // 将 `this.add()` 映射为 `this.$store.dispatch('increment')`
    }),
  },
};

它能帮助我们在页面中减少不少代码量。更复杂的操作可以查看 官方页面。

Module

我们想要给状态分模块管理,而不是将所有的状态一股脑的都放在一个 state 中导致状态过于臃肿,Module 就能帮我们办到。具体怎么实现呢?代码如下:

// 模块 A 的状态及触发更新的方法
const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

// 模块 B 的状态及触发更新的方法
const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

// Vuex 为我们提供了 modules 方法,可以将 store 分割成模块,每个模块都有属于自己的 state、getter
// mutation、action
const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

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

模块内部管理这自己的 state,比如 mutation 接收的第一个参数是该模块的局部状态对象。

const moduleA = {
  state: { count: 0 },
  mutations: {
    increment(state) {
      // 这里的 `state` 对象是模块的局部状态
      state.count++;
    },
  },
};

Vuex 使用实例

下面我们通过一个小实例讲 Vuex 的使用方法运用到实践当中,以便我们更好的巩固知识点。我们还是通过 CDN 的形式引入 Vue.js 和 Vuex,代码如下所示:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
  <script src="https://cdn.bootcss.com/vuex/3.1.3/vuex.min.js"></script>
  <title>Vuex</title>
</head>
<body>
  <div id="app">
    <div>{{ $store.state.count }}</div>
    <button @click="add">1</button>
    <button @click="dec">1</button>
  <div>
  <script>
    const store = new Vuex.Store({
      state: {
        count: 0
      },
      // 开启严格模式,开启严格模式后,必须通过 mutation 来修改状态
      strict: true,
      // 触发 state 中的 count 加减运算的方法
      mutations: {
        add(state) {
          state.count += 1
        },
        dec(state) {
          state.count -= 1
        }
      },
      getters: {
        // 过滤偶数的 getter
        filterEven: state => {
          return !(state.count % 2)
        }
      }
    })
    const app = new Vue({
      el: '#app',
      store, // 将 Vuex 生成的实例作为 Vue 生成实例的参数
      data: {
        message: 'Hello Vue!'
      },
      methods: {
        add() {
          // 触发加法
          this.$store.commit('add')
        },
        dec() {
          // 触发减法
          this.$store.commit('dec')
        }
      }
    }).$mount('#app');
  </script>
</body>
</html>

需要注意的是,静态资源的引入,Vuex 要在 Vue 的后面,因为 Vuex 内部是依赖 Vue,否则浏览器会报错。通过 Vuex.Store 生成实例建议使用 strict: true 严格模式,减少多人员参与项目时代码的紊乱。

上述代码执行后效果如下:

img

真实环境中 可能有些数据是通过异步来回去的,所以在这为想通过请求的方式来改变 state 中的数据,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://cdn.bootcss.com/vue/2.6.11/vue.min.js"></script>
  <script src="https://cdn.bootcss.com/vuex/3.1.3/vuex.min.js"></script>
  <title>Vuex</title>
</head>
<body>
  <div id="app">
    <div>{{ $store.state.count }}</div>
    <button @click="asyncAdd">异步加1</button>
    <button @click="asyncDec">异步减1</button>
  <div>
  <script>
    // 模拟请求数据,延迟 2 秒返回数据
    function AsyncData() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(1)
        }, 2000)
      })
    }

    const store = new Vuex.Store({
      state: {
        count: 0
      },
      // 开启严格模式,开启严格模式后,必须通过 mutation 来修改状态。
      strict: true,
      mutations: {
        add(state, num) {
          state.count += num
        },
        dec(state, num) {
          state.count -= num
        }
      },
      actions: {
        async add(ctx) {
          const num = await AsyncData()
          console.log('执行action:add')
          ctx.commit('add', num)
        },
        async dec(ctx) {
          const num = await AsyncData()
          console.log('执行action:dec')
          ctx.commit('dec', num)
        }
      },
      getters: {
        filterOdd: state => {
          return !(state.count % 2)
        }
      }
    })
    const app = new Vue({
      el: '#app',
      store,
      data: {
        message: 'Hello Vue!'
      },
      methods: {
        asyncAdd() {
          this.$store.dispatch('add')
        },
        asyncDec() {
          this.$store.dispatch('dec')
        }
      }
    }).$mount('#app');
  </script>
</body>
</html>

AsyncData 函数模拟接口请求延迟 2 秒返回要加的数据,要注意的是笔者在 actions 方法内执行了异步操作使用的是 async、await,低版本的浏览器还不能很好的支持它们,谷歌、火狐、360 极速等浏览器基本上已经支持。触发 actions 中的方法,需要在组件中调用的是 dispatch() 方法,要注意和 mutations 区分开。我们来看看浏览器的表现情况:

img

注意 Vuex 中异步的请求操作都需要放在 actions 中。

总结

Vuex 可以帮助我们管理好共享状态,但是也不是所有的应用都要用上 Vuex,需要对项目的短期和长期效益进行权衡,如果不是开发大型的单页应用,就不必使用 Vuex,因为这样会让项目变得繁琐冗余,简单的小应用可以通过结合 localStorage 封装一个简单的状态管理插件。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/353811.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux环境下(CentOS 7)安装Java(JDK8)

Linux环境下(CentOS 7)安装Java(JDK8) 一、安装教程 1.1 首先&#xff0c;进入oracle官网下载jdk8的安装包&#xff0c;下载地址如下&#xff0c;这里以 jdk-8u121-linux-x64.tar.gz安装包为例。 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-21…

2023美赛(MCM/ICM)数据汇总

2023美赛已经开始了十二个小时了&#xff0c;对于本次比赛&#xff0c;赛题 难度都不大。主要就是收集数据的问题 &#xff0c;为了更好地帮助大家选题&#xff0c;我们将 我们今天已经收集到的数据进行汇总&#xff0c;分享。其中&#xff0c;首先是A、E题目都提及的天气数据&…

C语言学习_DAY_4_判断语句if_else和分支语句switch_case【C语言学习笔记】

高质量博主&#xff0c;点个关注不迷路&#x1f338;&#x1f338;&#x1f338;&#xff01; 目录 1.案例引入 2.if判断语句的语法与注意事项 3.switch多分支语句的语法与注意事项 前言: 书接上回&#xff0c;我们已经学习了所有的数据类型、运算符&#xff0c;并且可以书写…

基于matlab/simulink的风光柴储微电网仿真建模

模型是基于之前的风光储系统上增加一部分柴油发电机系统&#xff0c;后面文章我会单独介绍柴油机这一部分&#xff0c;主要应用在船舶电力系统&#xff0c;一般小型电网黑启动也会用到。 风光柴储微电网发电系统是一种小型发电系统&#xff0c;同时具备并网运行和孤岛运行的功能…

气敏电阻的原理,结构,分类及应用场景总结

🏡《总目录》 目录 1,概述2,结构3,工作原理4,分类4.1,加热方式分类4.2,材料分类4.3,氧化还原分类5,应用场景6,总结1,概述 气敏电阻是指电阻值随着环境中某种气体的浓度变化而变化的电阻,本文对其工作原理,结构,分类和应用场景进行总结。 2,结构 气敏电阻由防爆…

Leetcode(每日一题)——1237. 找出给定方程的正整数解

摘要 1237. 找出给定方程的正整数解 一、暴力求解 根据题目给出的x和y的取值范围&#xff0c;枚举所有的 x,y数对&#xff0c;保存满足f(x,y)z的数对&#xff0c;最后返回结果。 /*** description 使用的暴力法 直接遍历符合的就添加到结果中* param: customfunction* param…

能不能做好性能测试,要看你有没有性能测试思维

获取性能需求 01、用户数信息 1、调查系统当前和未来使用的用户数 系统用户数 本系统目前注册的用户数&#xff0c;注册用户数并不代表他会每天并且无时无刻的使用着。 在线用户数 同时在线对系统进行操作的用户数量&#xff08;相当于混合场景&#xff09; 并发用户数 …

第9天-商品服务(电商核心概念,属性分组开发及分类和品牌的级联更新)

1.电商核心概念 1.1.SPU与SKU SPU&#xff1a;Standard Product Unit&#xff08;标准化产品单元&#xff09; 是商品信息聚合的最小单位&#xff0c;是一组可复用、易检索的标准化信息的集合&#xff0c;该集合描述了一个 产品的特性。 决定商品属性的值 SKU&#xff1a;Stock…

第43天| 123.买卖股票的最佳时机III、 188.买卖股票的最佳时机IV

1.题目链接&#xff1a;123. 买卖股票的最佳时机 III 题目描述&#xff1a; 给定一个数组&#xff0c;它的第 i 个元素是一支给定的股票在第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。 注意&#xff1a;你不能同时参与多笔交易&#…

基于深度神经网络的3D模型合成【Transformer vs. CNN】

本文介绍用于3D模型合成的transformer网络与深度卷积网络。 推荐&#xff1a;使用 NSDT场景设计器 快速搭建 3D场景。 1、概述 从单一视角合成 3D 数据是一种基本的人类视觉功能&#xff0c;这对计算机视觉算法来说极具挑战性&#xff0c;这是一个共识。 但在 3D 传感器&#…

Fedora Linux未来五年规划

Fedora 委员会一直致力于起草战略计划&#xff0c;以帮助 Fedora Linux 更好地发展。近日 Fedora 委员会公布了一份 “《未来五年的 Fedora Linux 》” 战略计划草案&#xff0c;这份草案里面包含了他们的雄心壮志&#xff1a;每周将 Fedora 的活跃贡献者人数增加一倍。 Fedora…

如何获取docpelx求解目标函数后的数据;在解决目标优化问题之后,如何获取相关数据;获取决策变量的具体数值

获取优化问题的自变量取值和目标函数取值 说明通过 mdl.integer_var() 定义的决策变量&#xff0c;获取求解值决策变量获取目标函数取值获取具体代码&#xff1a;通过 mdl.continuous_var_list() 定义的决策变量&#xff0c;获取求解值具体代码说明 本次的代码环境是 python中…

【WEB安全】SQL注入挖掘

文章目录前言一、sql注入的分类注入漏洞存在位置二、漏洞挖掘Google语法疑似注入点手工挖掘批量挖取此类漏洞已知sql注入漏洞挖掘总结免责声明&#xff1a;前言 2021年OWASP发布漏洞威胁榜单&#xff0c;SQL注入从第一名下降到第三&#xff08;https://owasp.org/Top10/&#…

从0开始学python -34

Python3 输入和输出-2 读和写文件 open() 将会返回一个 file 对象&#xff0c;基本语法格式如下: open(filename, mode)filename&#xff1a;包含了你要访问的文件名称的字符串值。mode&#xff1a;决定了打开文件的模式&#xff1a;只读&#xff0c;写入&#xff0c;追加等。…

数据分析| Pandas200道练习题,使用Pandas连接MySQL数据库

文章目录使用Pandas连接数据库编码环境依赖包read_sql_query()的使用read_sql_table()的使用read_sql() 函数的使用to_sql()写入数据库的操作删除操作更新操作总结&#xff1a;使用Pandas连接数据库 通过pandas实现数据库的读&#xff0c;写操作时&#xff0c;首先需要进行数据…

kubernetes教程 -- k8s组件

k8s组件 maste节点 apiServer&#xff1a;资源操作的唯一入口&#xff0c;接受用户的输入&#xff0c;提供认证&#xff0c;控制访问等功能Scheduler&#xff1a;负责集群的资源调度&#xff0c;按照预定的调度策略将Pod调度到相应的node节点上controllerManager&#xff1a;负…

JVM学习篇剖析JVM类加载机制

1. 类加载运行全过程 当我们用java命令运行某个类的main函数启动程序时&#xff0c;首先需要通过类加载器把主类加载到JVM。 public class Math {private static int initData 6666;public static User user new User();private int compute() {int a 1;int b 3;int c (…

【vue后台管理系统】基于Vue+Element-UI+ECharts开发通用管理后台(下)

文章目录面包屑导航制作效果展示思路分析代码实现过程需求优化用户管理页面效果展示新增用户表单实现table组件编写分页功能编写搜索功能编写附&#xff1a;ES6的解构赋值数组模型的解构&#xff08;Array&#xff09;对象模型的解构&#xff08;Object&#xff09;面包屑导航制…

[Linux篇] Linux常见命令和权限

文章目录使用XShell登录Linux1.Linux常用基本命令&#xff1a;1.1 ls&#xff08;列出当前的目录下都有哪些文件和目录&#xff09;1.2 cd (change directory 切换目录)1.3 pwd&#xff08;查看当前目录的绝对路径&#xff09;1.4 touch&#xff08;创建文件&#xff09;1.5 ca…

数据库系统是什么?它由哪几部分组成?

数据库系统&#xff08;Database System&#xff0c;DBS&#xff09;由硬件和软件共同构成。硬件主要用于存储数据库中的数据&#xff0c;包括计算机、存储设备等。软件部分主要包括数据库管理系统、支持数据库管理系统运行的操作系统&#xff0c;以及支持多种语言进行应用开发…