vue.js ——Vuex

news2024/9/21 14:43:21

基本概念

vue进行开发过程中有没有遇到这样一种场景,就是有些时候一些数据是一种通用的共享数据(比如登录信息),那么这类数据在各个组件模块中可能都会用到,如果每个组件中都去后台重新获取那么势必会造成性能浪费,为了解决这一问题一个新的状态管理工具 - vuex就应运而生
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

什么是“状态管理模式”?

这个状态自管理应用包含以下几个部分:

  • 状态,驱动应用的数据源;
  • 视图,以声明方式将状态映射到视图;
  • 操作,响应在视图上的用户输入导致的状态变化。

安装方式

CDN引用

https://unpkg.com/vuex@4

Unpkg.com 提供了基于 npm 的 CDN 链接。以上的链接会一直指向npm 上发布的最新版本。
您也可以通过 https://unpkg.com/vuex@4.0.0/dist/vuex.global.js 这样的方式指定特定的版本。

Npm
npm install vuex@next --save
Yarn
yarn add vuex@next --save

核心概念

State

  • 单一状态树
    Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。至此它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。单一状态树让我们能够直接地定位任一特定的状态片段,在调试的过程中也能轻易地取得整个当前应用状态的快照。
  • 在 Vue 组件中获得 Vuex 状态
    由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态:
const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return store.state.count
    }
  }}

每当store.state.count变化的时候, 都会重新求取计算属性,并且触发更新相关联的 DOM
Vuex 通过 Vue 的插件系统将 store 实例从根组件中“注入”到所有的子组件里。且子组件能通过this.$store访问到。让我们更新下Counter的实现:

const Counter = {
  template: `<div>{{ count }}</div>`,
  computed: {
    count () {
      return this.$store.state.count
    }
  }}
  • mapState 辅助函数
    当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。
    为了解决这个问题,我们可以使用 mapState辅助函数帮助我们生成计算属性,让你少按几次键
import { mapState } from 'vuex'
export default {
  computed: mapState({
       count: state => state.count,  // 箭头函数可使代码更简练
    // 传字符串参数 'count' 等同于 `state => state.count`
    countAlias: 'count',
    // 为了能够使用 `this` 获取局部状态,必须使用常规函数
    countPlusLocalState (state) {
      return state.count + this.localCount
    }
  })}
  • 对象展开运算符
    mapState函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给computed属性。但是自从有了对象展开运算符【…】,我们可以极大地简化写法:
computed: {
  localComputed () { /* ... */ },
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({
    // ...
  })}

对象展开运算符
var obj = {a:1,b:2}
var obj1 = {c:3,d:4}
var obj2 ={…obj,…obj1}
var obj3 = {…obj,a:8,w:66}
var obj4 ={…obj,a:8,w:66,…obj1}
console.log(obj); //{a: 1, b: 2}
console.log(obj1); //{c: 3, d: 4}
console.log(obj2); //{a: 1, b: 2,c: 3, d: 4}
console.log(obj3); //{a: 8, b: 2, w: 66}
console.log(obj4); //{a: 8, b: 2, w: 66, c: 3, d: 4}

Getter

我们需要从 store 中的 state 中派生出一些状态,如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它——无论哪种方式都不是很理想。
Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。
从 Vue 3.0 开始,getter 的结果不再像计算属性一样会被缓存起来
Getter 接受 state 作为其第一个参数:

const store = createStore({
  state: {
    todos: [
      { id: 1, text: '...', done: true },
      { id: 2, text: '...', done: false }
    ]
  },
  getters: {
    doneTodos (state) {
      return state.todos.filter(todo => todo.done)
    }
  }})
  • 通过属性访问
    Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值:
store.getters.doneTodos 

Getter 也可以接受其他 getter 作为第二个参数

getters: {
  // ...
  doneTodosCount (state, getters) {
    return getters.doneTodos.length
  }}
  • 通过方法访问
    你也可以通过让 getter 返回一个函数,来实现给 getter 传参。在你对 store 里的数组进行查询时非常有用。
getters: {
  getTodoById: (state) => (id) => {
    return state.todos.find(todo => todo.id === id)
  }}
store.getters.getTodoById(2)

getter 在通过方法访问时,每次都会去进行调用,而不会缓存结果。

  • mapGetters 辅助函数
    mapGetters辅助函数仅仅是将store中的getter映射到局部计算属性
import { mapGetters } from 'vuex'
export default {
  // ...
  computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }}

Mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:

const store = createStore({
  state: {
    count: 1
  },
  mutations: {
    increment (state) {
      // 变更状态
      state.count++
    }
  }})
  • 提交载荷(Payload)
    你可以向 store.commit 传入额外的参数,即 mutation 的载荷(payload):
mutations: {
  increment (state, n) {
    state.count += n
  }}
store.commit('increment', 10)
  • 对象风格的提交方式
    提交 mutation 的另一种方式是直接使用包含 type 属性的对象:
store.commit({
  type: 'increment',
  amount: 10})

当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此处理函数保持不变:

mutations: {
  increment (state, payload) {
    state.count += payload.amount
  }}
  • Mutation 必须是同步函数
    一条重要的原则就是要记住 mutation 必须是同步函数

Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。
  • 分发 Action
    Action 通过 store.dispatch 方法触发:
store.dispatch('increment')
actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }}
  • 在组件中分发 Action
    你在组件中使用this.$store.dispatch(‘xxx’)分发 action,或者使用mapActions辅助函数将组件的methods映射为store.dispatch调用(需要先在根节点注入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

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿
为了解决以上问题,Vuex允许我们将store分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块

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

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

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }})

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

进阶

项目结构

Vuex 并不限制你的代码结构。但是,它规定了一些需要遵守的规则:

  • 应用层级的状态应该集中到单个 store 对象中。
  • 提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
  • 异步逻辑都应该封装到 action 里面。
    只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation 和 getter 分割到单独的文件。
    对于大型应用,我们会希望把 Vuex 相关代码分割到模块中。下面是项目结构示例:
    在这里插入图片描述

热重载

使用 webpack 的 Hot Module Replacement API,Vuex 支持在开发过程中热重载 mutation、module、action 和 getter。你也可以在 Browserify 中使用 browserify-hmr 插件。
对于 mutation 和模块,你需要使用 store.hotUpdate() 方法:

// store.js
import { createStore } from 'vuex'
import mutations from './mutations'
import moduleA from './modules/a'
const state = { ... }
const store = createStore({
  state,
  mutations,
  modules: {
    a: moduleA
  }})
if (module.hot) {
  // 使 action 和 mutation 成为可热重载模块
  module.hot.accept(['./mutations', './modules/a'], () => {
    // 获取更新后的模块
    // 因为 babel 6 的模块编译格式问题,这里需要加上 `.default`
    const newMutations = require('./mutations').default
    const newModuleA = require('./modules/a').default
    // 加载新模块
    store.hotUpdate({
      mutations: newMutations,
      modules: {
        a: newModuleA
      }
    })
  })}

动态模块热重载
如果你仅使用模块,你可以使用 require.context 来动态地加载或热重载所有的模块。

// store.js
import { createStore } from 'vuex'
// 加载所有模块。function loadModules() {
  const context = require.context("./modules", false, /([a-z_]+)\.js$/i)
  const modules = context
    .keys()
    .map((key) => ({ key, name: key.match(/([a-z_]+)\.js$/i)[1] }))
    .reduce(
      (modules, { key, name }) => ({
        ...modules,
        [name]: context(key).default
      }),
      {}
    )

  return { context, modules }}
const { context, modules } = loadModules()
const store = new createStore({
  modules})
if (module.hot) {
  // 在任何模块发生改变时进行热重载。
  module.hot.accept(context.id, () => {
    const { modules } = loadModules()

    store.hotUpdate({
      modules
    })
  })}

组合式api

可以通过调用 useStore 函数,来在 setup 钩子函数中访问 store。这与在组件中使用选项式 API 访问 this.$store 是等效的。

import { useStore } from 'vuex'
export default {
  setup () {
    const store = useStore()
  }}

访问 State 和 Getter
为了访问 state 和 getter,需要创建 computed 引用以保留响应性,这与在选项式 API 中创建计算属性等效。

import { computed } from 'vue'import { useStore } from 'vuex'
export default {
  setup () {
    const store = useStore()

    return {
      // 在 computed 函数中访问 state
      count: computed(() => store.state.count),

      // 在 computed 函数中访问 getter
      double: computed(() => store.getters.double)
    }
  }}

访问 Mutation 和 Action
要使用 mutation 和 action 时,只需要在 setup 钩子函数中调用 commit 和 dispatch 函数。

import { useStore } from 'vuex'
export default {
  setup () {
    const store = useStore()
    return {
      // 使用 mutation
      increment: () => store.commit('increment'),

      // 使用 action
      asyncIncrement: () => store.dispatch('asyncIncrement')
    }
  }}

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

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

相关文章

R语言30分钟入门

1. 环境&安装 R是支持win、linux合macos的 完整参考&#xff1a;https://zhuanlan.zhihu.com/p/596324321?utm_id0 主要是安装&#xff1a;1、R环境&#xff1b;2、rstudio开发环境&#xff08;后面主要是用rstudio&#xff0c;也可以用vscode&#xff09; 1.1. rstud…

异常 Exception 02

异常 Exception 02 六、异常处理1、基本介绍2、异常处理的方式3、示意图 try-catchthrows1、介绍2、注意事项 自定义异常1、基本概念2、自定义异常的步骤3、实例4、throw和throws的区别 六、异常处理 1、基本介绍 异常处理就是当异常发生时,对异常处理的方式。 2、异常处理的…

佳易王物流快运物流单打印登记查询系统软件操作教程

一、前言&#xff08;编程应用实例系列&#xff09;&#xff1a; 佳易王物流快运物流单打印登记查询系统软件操作教程 软件有试用版&#xff0c;可以下载试用&#xff0c;了解软件操作和软件功能。 软件试用版下载可以点击最下方官网卡片 软件为绿色免安装版&#xff0c;下载…

2023-简单点-yolox-pytorch代码解析(二)-nets/yolo.py

yolox-pytorch&#xff1a;nets/yolo.py yolox网络结构yolox-pytorch目录今天解析注释nets/yolo.py yolox网络结构 yolox-pytorch目录 nets目录 今天解析注释nets/yolo.py import torch import torch.nn as nnfrom .darknet import BaseConv, CSPDarknet, CSPLayer, DWConv##…

各种与梅洛相关的葡萄酒知识

梅洛葡萄是可以通过其松散的大浆果串来识别的&#xff0c;与赤霞珠葡萄相比&#xff0c;这种颜色的蓝色/黑色调更少&#xff0c;皮肤更薄&#xff0c;单宁更少。与赤霞珠相比&#xff0c;梅洛葡萄的糖含量往往更高&#xff0c;苹果酸含量较低。梅洛在寒冷的土壤中茁壮成长&…

【云原生系列】Kubernetes知识点

目录 概念 基础架构 单master节点 多master节点 组件 Master节点核心组件 其他组件 请求发送流程 插件 核心资源 调度资源 Pod 创建pod组件间调用流程 pod生命周期&#xff1a; 初始化容器 镜像拉取策略 重启策略 钩子函数 探针 探针的实现方式 DownwardAP…

【Qt基础之QPalette实例电子时钟】

# 简介 借助`QLCDNumber`实现电子时钟,可以随意拖拽到桌面任意位置,鼠标右键进行关闭,用于实践`QPalette`类、`QTimer`的使用以及`mousePressEvent`\`mouseMoveEvent`\`mouseDoubleClickEvent`事件处理函数的使用。可在此基础上扩展其他应用,参看Qt帮助手册。 # QPalette …

画中画视频剪辑:批量制作画中画,提升视频制作技能

在视频制作过程中&#xff0c;画中画是一种常见的视觉效果&#xff0c;它能够使多个视频片段在同一画面中展示&#xff0c;增加信息的丰富度和视觉的吸引力。这种效果通常用于增加信息的丰富度&#xff0c;如在新闻节目中&#xff0c;同时展示主持人和采访对象的画面。画中画也…

windows下使用iperf3

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、使用步骤1.下载2.解压3.测试1.作为服务器使用2.作为客户端使用 总结 前言 windows使用iperf3和linux是一样的&#xff0c;而且可以相互操作。 一、使用步骤…

Java最难的语法<泛型>

时间过得很快&#xff0c;我们马上就进入了&#xff0c;Java最难语法的学习&#xff0c;加油吧&#xff01; 1.包装类 想要学好泛型就要了解包装类。 在Java中&#xff0c;由于基本类型不是继承自Object&#xff0c;为了在泛型代码中可以支持基本类型&#xff0c;Java给每个…

Python入门06布尔值

目录 1 什么是布尔值2 怎么生成布尔值3 在控制程序中使用布尔值4 数据过滤、排序和其他高级操作总结 1 什么是布尔值 首先我们要学习一下布尔值的定义&#xff0c;布尔值是一种数据类型&#xff0c;它只有两个可能的值&#xff1a;True&#xff08;真&#xff09;或 False&…

scikit-opt几种数值模拟退火的代码示例,和参数详解,以及基础模拟退火的原理代码示例

python基础模拟退火原理示例 模拟退火的特性决定了一般可以用于算法的调参&#xff0c;相比较遗传算法来说&#xff0c;普遍更快一些&#xff0c;但是也更容易陷入局部最优。相对来说&#xff0c;遗传算法的更新解机制是在最每一个局部最优解附近盘旋游荡&#xff0c;则更容易…

View绘制

onDraw 绘制 canvas 画布 paint 画笔 坐标系 x y x 0 y 0 则屏幕左上角 y从上往下值增加 像素转换 dp2px 画线line drawLine 圆circle drawCircle drawPath: 在onSizeChanged 时候初始化 addCircle 添加圆 CW顺时针 CCW 逆时针 CW CCW填充规则不同 填充规则: 默认 …

NX二次开发UF_MTX2_vec_multiply_t 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_MTX2_vec_multiply_t Defined in: uf_mtx.h void UF_MTX2_vec_multiply_t(const double vec [ 2 ] , const double mtx [ 4 ] , double vec_product [ 2 ] ) overview 概述 Ret…

邮政快递物流查询,将指定某天签收的单号筛选出来

批量查询邮政快递单号的物流信息&#xff0c;将指定某天签收的单号筛选出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 邮政快递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;并登录 步骤2&#xff1a;点击主界面左…

python-nmap库使用教程(Nmap网络扫描器的Python接口)(功能:主机发现、端口扫描、操作系统识别等)

文章目录 Python-nmap库使用教程前置条件引入python-nmap创建Nmap扫描实例执行简单的主机发现&#xff08;nmap -sn&#xff09;示例&#xff0c;我有一台主机配置为不响应 ICMP 请求&#xff0c;但使用nmap -sn&#xff0c;仍然能够探测到设备&#xff1a; 端口扫描扫描特定端…

线性回归 调试方法

调试方法 特征缩放 对于某些不具有比较性的样本特征 x i x_i xi​ &#xff08;比如对其他的x来说 x i x_i xi​ 相当大或者相当小&#xff09;&#xff0c;梯度下降的过程可能会非常漫长&#xff0c;并且可能来回波动才能最后收敛到全局的最小值。 在这样的情况下&#xff…

SAP BW层级结构小结属性数据源+专家例程实现层级结构增强加载

作者 idan lian 如需转载备注出处 BW信息对象-层级结构 RSH1 维护信息对象层级 这里的文本描述对应T表中的描述&#xff0c;文本数据源加载之后有数据 信息对象层级H表 以上描述都是根据自我理解翻译的&#xff0c;非官方翻译 层级标识&#xff1a;自动生成&#xff0c;其实…

CCF CSP认证 历年题目自练Day50

题目 试题编号&#xff1a; 201809-3 试题名称&#xff1a; 元素选择器 时间限制&#xff1a; 1.0s 内存限制&#xff1a; 256.0MB 问题描述&#xff1a; 题目分析&#xff08;个人理解&#xff09; 还是先理解题意&#xff0c;关于html的部分&#xff0c;可以按照样例画出…

2000-2021年各省人口密度数据

2000-2021年各省人口密度数据 1、时间&#xff1a;2000-2021年 2、指标&#xff1a;地区、年份、年末常住总人口(万人&#xff09;、面积&#xff08;平方千米&#xff09;、人口密度&#xff08;人/平方千米&#xff09; 3、来源&#xff1a;各省年鉴、统计年鉴、各省统计局…