VueSupercharge 精通指南:构建超级状态管理 Vue.js 应用

一、介绍

1.1 Vuex 是什么 ?

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

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

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

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

以下是一个表示“单向数据流”理念的简单示意:

但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:

  • 多个视图依赖于同一状态。

  • 来自不同视图的行为需要变更同一状态。

对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。

Vuex就是把组件的共享状态抽取出来,以一个全局单例模式管理 。
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。

1.3 安装

npm install vuex@next --save

1.4 简单的Vuex使用

1.4.1 store.js

import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {},actions: {},
})

1.4.2 main.js

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import store from "./store";Vue.config.productionTip = false/* eslint-disable no-new */
new Vue({el: '#app',components: { App },template: '<App/>',store
})

1.4.3 App.vue

<template><div><my-addition></my-addition><p>----------------------------------</p><my-subtraction></my-subtraction></div>
</template><script>
import Addition from "./components/Addition";
import Subtraction from "./components/Subtraction";export default {data() {return {};},components: {'my-addition': Addition,'my-subtraction': Subtraction}
}
</script><style></style>

1.4.4 Addition.vue

<template><div><!-- 组件访问State中数据的第一种方式   --><h3>当前最新的count值为:{{$store.state.count}}</h3><button>+1</button></div>
</template><script>
export default {name: "Addition",data() {return {};}
}
</script><style scoped></style>

1.4.5 Subtraction.vue

<template><div><h3>当前最新的count值为:{{$store.state.count}}</h3><button>-1</button></div>
</template><script>
export default {name: "Subtraction",data() {return {};}
}
</script><style scoped></style>

二、State

2.1 单一状态树

  • Vuex 使用单一状态树,用一个对象就包含了全部的应用层级状态。

  • 它便作为一个“唯一数据源 (SSOT)”而存在。这也意味着,每个应用将仅仅包含一个 store 实例。

2.2 方式一:通过$store获取State中数据

$store.state.count

2.3 方式二:通过mapState获取State中数据(推荐)

// 组件访问State中数据的第二种方式--引入
import {mapState} from 'vuex'// 将全局数据,映射为当前组件的计算属性
...mapState(['count'])// 模版中使用
<template><div><h3>当前最新的count值为:{{count}}</h3><button>-1</button></div>
</template>

三、Mutation

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

3.1 方式一:使用commit触发mutation

使用commit触发mutation

// store.js
export default new Vuex.Store({state: {count: 0},mutations: {add(state) {state.count++;}},actions: {},
})// Adition.vue
<template><div><!-- 组件访问State中数据的第一种方式   --><h3>当前最新的count值为:{{$store.state.count}}</h3><button @click="addHandler">+1</button></div>
</template><script>
export default {name: "Addition",data() {return {};},methods: {addHandler() {// 这种方式是不合法的!!!// this.$store.state.count++;// 触发mutation的第一种方式this.$store.commit('add')}}
}
</script><style scoped></style>

带参数的mutation

// store.js
import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {add(state) {state.count++;},// 第二位就是,传入的参数。如果是多个参数可以传入对象addN(state, step) {state.count += step;},sub(state) {state.count--;},},actions: {},
})
// Addition.vue
<template><div><!-- 组件访问State中数据的第一种方式   --><h3>当前最新的count值为:{{$store.state.count}}</h3><button @click="addHandler">+1</button><button @click="addNHandler">+N</button></div>
</template><script>
export default {name: "Addition",data() {return {};},methods: {addHandler() {// 这种方式是不合法的!!!// this.$store.state.count++;// 触发mutation的第一种方式this.$store.commit('add')},addNHandler() {this.$store.commit('addN', 3)}}
}
</script><style scoped></style>

3.2 方式二:使用mapMutation触发mutation(推荐)

store.js

import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {add(state) {state.count++;},addN(state, step) {state.count += step;},sub(state) {state.count--;},subN(state, step) {state.count -= step;},},actions: {},
})

Subtraction.vue

<template><div><h3>当前最新的count值为:{{count}}</h3><button @click="subHandler">-1</button><button @click="subNHandler">-N</button></div>
</template><script>
// 组件访问State中数据的第二种方式--引入
import {mapState, mapMutations} from 'vuex'export default {name: "Subtraction",data() {return {};},computed: {// 将全局数据,映射为当前组件的计算属性...mapState(['count'])},methods: {...mapMutations(['sub', 'subN']),// 将全局mutations函数映射为组件中的函数subHandler() {this.sub();},subNHandler() {this.subN(3)}}
}
</script><style scoped></style>


四、Action

Action的作用是执行异步函数,因为mutation中无法执行异步函数。在mutation中使用异步函数会导致state的状态无法被及时追踪导致代码异常!!!

4.1 方式一:使用dispatch调用Action中的异步函数

4.1.1 store.js

import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {add(state) {// setTimeout(() => {//   // 不要在mutations中执行异步操作,会造成vuex存储状态不可追踪//   state.count++;// }, 1000)state.count++;},addN(state, step) {state.count += step;},sub(state) {state.count--;},subN(state, step) {state.count -= step;},},actions: {// context: 可以理解为当前的Vuex.Store实例对象addAsync(context) {setTimeout(() => {// 在 actions 中,不能直接修改 state 中的数据// 必须通过 context.commit() 触发某个 mutations 才行context.commit('add')}, 1000)},addNAsync(context, step) {setTimeout(() => {// 在 actions 中,不能直接修改 state 中的数据// 必须通过 context.commit() 触发某个 mutations 才行context.commit('addN', step)}, 1000)}},
})

4.1.2 Addition.vue

<template><div><!-- 组件访问State中数据的第一种方式   --><h3>当前最新的count值为:{{$store.state.count}}</h3><button @click="addHandler">+1</button><button @click="addNHandler">+N</button><button @click="addHandlerAsync">+1 Async</button><button @click="addNHandlerAsync">+N Async</button></div>
</template><script>
export default {name: "Addition",data() {return {};},methods: {addHandler() {// 这种方式是不合法的!!!// this.$store.state.count++;// 触发mutation的第一种方式this.$store.commit('add')},addNHandler() {this.$store.commit('addN', 3)},addHandlerAsync() {// 这里的 dispatch 专门用来触发action函数this.$store.dispatch('addAsync')},addNHandlerAsync() {// 这里的 dispatch 专门用来触发action函数this.$store.dispatch('addNAsync', 3)}}
}
</script><style scoped></style>

4.2 方式二:使用mapAction调用Action中的异步函数

4.2.1 store.js

import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {add(state) {// setTimeout(() => {//   // 不要在mutations中执行异步操作,会造成vuex存储状态不可追踪//   state.count++;// }, 1000)state.count++;},addN(state, step) {state.count += step;},sub(state) {state.count--;},subN(state, step) {state.count -= step;},},actions: {// context: 可以理解为当前的Vuex.Store实例对象addAsync(context) {setTimeout(() => {// 在 actions 中,不能直接修改 state 中的数据// 必须通过 context.commit() 触发某个 mutations 才行context.commit('add')}, 1000)},addNAsync(context, step) {setTimeout(() => {// 在 actions 中,不能直接修改 state 中的数据// 必须通过 context.commit() 触发某个 mutations 才行context.commit('addN', step)}, 1000)},subAsync(context) {setTimeout(() => {context.commit('sub')}, 1000)},subNAsync(context, step) {setTimeout(() => {context.commit('subN', step)}, 1000)}},
})

4.2.2  Subtraction.vue

<template><div><h3>当前最新的count值为:{{count}}</h3><button @click="subHandler">-1</button><button @click="subNHandler">-N</button><button @click="subHandlerAsync">-1 Async</button><button @click="subNHandlerAsync">-N Async</button></div>
</template><script>
// 组件访问State中数据的第二种方式--引入
import {mapState, mapMutations, mapActions} from 'vuex'export default {name: "Subtraction",data() {return {};},computed: {// 将全局数据,映射为当前组件的计算属性...mapState(['count'])},methods: {...mapMutations(['sub', 'subN']),...mapActions(['subAsync', 'subNAsync']),// 将全局mutations函数映射为组件中的函数subHandler() {this.sub();},subNHandler() {this.subN(3)},subHandlerAsync() {this.subAsync();},subNHandlerAsync() {this.subNAsync(3)}}
}
</script><style scoped></style>

五、Getters

Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。

5.1 创建Getter方法

import Vue from 'vue'
import Vuex from 'vuex'Vue.use(Vuex)export default new Vuex.Store({state: {count: 0},mutations: {add(state) {// setTimeout(() => {//   // 不要在mutations中执行异步操作,会造成vuex存储状态不可追踪//   state.count++;// }, 1000)state.count++;},addN(state, step) {state.count += step;},sub(state) {state.count--;},subN(state, step) {state.count -= step;},},actions: {// context: 可以理解为当前的Vuex.Store实例对象addAsync(context) {setTimeout(() => {// 在 actions 中,不能直接修改 state 中的数据// 必须通过 context.commit() 触发某个 mutations 才行context.commit('add')}, 1000)},addNAsync(context, step) {setTimeout(() => {// 在 actions 中,不能直接修改 state 中的数据// 必须通过 context.commit() 触发某个 mutations 才行context.commit('addN', step)}, 1000)},subAsync(context) {setTimeout(() => {context.commit('sub')}, 1000)},subNAsync(context, step) {setTimeout(() => {context.commit('subN', step)}, 1000)}},getters: {showNum(state) {return '当前最新的数量是【' + state.count + '】';}}
})

5.2 方法一:$store.getter调用

<template><div><!-- 组件访问State中数据的第一种方式   --><h3>{{$store.getters.showNum}}</h3><button @click="addHandler">+1</button><button @click="addNHandler">+N</button><button @click="addHandlerAsync">+1 Async</button><button @click="addNHandlerAsync">+N Async</button></div>
</template><script>
export default {name: "Addition",data() {return {};},methods: {addHandler() {// 这种方式是不合法的!!!// this.$store.state.count++;// 触发mutation的第一种方式this.$store.commit('add')},addNHandler() {this.$store.commit('addN', 3)},addHandlerAsync() {// 这里的 dispatch 专门用来触发action函数this.$store.dispatch('addAsync')},addNHandlerAsync() {// 这里的 dispatch 专门用来触发action函数this.$store.dispatch('addNAsync', 3)}}
}
</script><style scoped></style>

5.3 方法二:mapGetters方式调用

<template><div><h3>{{showNum}}</h3><button @click="subHandler">-1</button><button @click="subNHandler">-N</button><button @click="subHandlerAsync">-1 Async</button><button @click="subNHandlerAsync">-N Async</button></div>
</template><script>
// 组件访问State中数据的第二种方式--引入
import {mapState, mapMutations, mapActions, mapGetters} from 'vuex'export default {name: "Subtraction",data() {return {};},computed: {// 将全局数据,映射为当前组件的计算属性...mapState(['count']),// 将全局的getters,映射为当前组件的计算属性...mapGetters(['showNum'])},methods: {...mapMutations(['sub', 'subN']),...mapActions(['subAsync', 'subNAsync']),// 将全局mutations函数映射为组件中的函数subHandler() {this.sub();},subNHandler() {this.subN(3)},subHandlerAsync() {this.subAsync();},subNHandlerAsync() {this.subNAsync(3)}}
}
</script><style scoped></style>

六、其他

6.1 modules

Module | Vuex

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 的状态

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GPT APP的开发步骤

开发一个GPT&#xff08;Generative Pre-trained Transformer&#xff09; Store&#xff08;存储&#xff09;涉及到使用预训练的语言模型&#xff08;例如GPT-3&#xff09;来生成和管理内容。以下是一般的步骤&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&…

P4学习(四)实验一:Basic Forwarding

目录 一.前置知识二.实验过程记录1.找到实验文件2.拓扑图3.明确实验内容4.实验初体验 三. 编写解决方案1.Parse部分1.1 Code1.2 知识点解析 2.Ingress部分2.1 Code2.2 知识点解析 3.Deparse部分3.1 Code3.2 知识点 四.实验完成测试 一.前置知识 Linux基础命令(vim)V!Model的架…

wins安装paddle框架

一、安装 https://www.paddlepaddle.org.cn/install/quick?docurl/documentation/docs/zh/install/pip/windows-pip.html 装包&#xff08;python 的版本是否满足要求&#xff1a; 3.8/3.9/3.10/3.11/3.12&#xff0c; pip 版本为 20.2.2 或更高版本 &#xff09; CPU 版:…

day01_ Java概述丶开发环境的搭建丶常用DOS命令

编程常识 什么是编程&#xff1f; 所谓编程&#xff0c;就是人们可以使用编程语言对计算机下达命令&#xff0c;让计算机完成人们需要的功能。 编程语言的发展历程 第一代&#xff1a;机器语言 &#xff0c;机器语言由数字组成所有指令。计算器解析运行速度&#xff0c;最快…

DoYocms靶场(好像咩啥漏洞?)

这个doyocms靶场感觉没什么漏洞&#xff1f;&#xff1f;&#xff1f;不知道是不是我的错觉&#xff0c;还是说我的靶场配置有问题 OnlyOne 漏洞&#xff1a;支付漏洞 我们可以在靶场中找到一个商品购买界面 于是就可以先抓个包,就可以发现过滤的死死的 根本找不到鉴权参数&am…

《教师》期刊是什么级别的期刊?是正规期刊吗?能评职称吗?

《教师》杂志主要发表大中小学、幼儿园、特殊教育学校等各级各类学校教师的优秀教育、教学科研成果&#xff0c;旨在促进国内外学术交流&#xff0c;服务国家科学文化建设的需要。从创刊以来一直坚持“服务基础教育&#xff1b;探究教研教改&#xff1b;提高教师素质&#xff1…

SpringCloud GateWay 在全局过滤器中注入OpenFeign网关后无法启动

目录 一、问题 二、原因 1、修改配置 2、添加Lazy注解在client上面 3、启动成功 一、问题 当在gateway的全局过滤器GlobalFilter中注入OpenFeign接口的时候会一直卡在路由中&#xff0c;但是不会进一步&#xff0c;导致启动未成功也未报错失败 2024-01-18 22:06:59.299 I…

网工内推 | 运维工程师,最高10K*15薪,思科认证优先

01 乐歌股份 招聘岗位&#xff1a;服务器运维工程师 职责描述&#xff1a; 1、负责公司云上云下所有服务器的日常运维工作&#xff0c;包括应用部署、巡检、备份、日志、监控&#xff0c;故障处理&#xff0c;性能优化等&#xff0c;保障公司相关系统稳定运行。 2、为开发、测…

MyBatisPlus学习笔记三-核心功能

接上篇&#xff1a; MyBatisPlus学习笔记二-CSDN博客 1、核心功能-IService开发基础业务接口 1.1、介绍 1.2、引用依赖 1.3、配置文件 1.4、用例-新增 1.5、用例-删除 1.6、用例-根据id查询 1.7、用例-根据ids查询 2、核心功能-IService开发复杂业务接口 2.1、实例-更新 3、…

JVM工作原理与实战(十九):运行时数据区-方法区

专栏导航 JVM工作原理与实战 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、运行时数据区 二、方法区 1.方法区介绍 2.方法区在Java虚拟机的实现 3.类的元信息 4.运行时常量池 5.字符串常量池 6.静态变量的存储 总结 前言 JVM作为Java程序的运行环境…

springcloud-cloud provider-payment8001微服务提供者支付Module模块

文章目录 IDEA新建project工作空间cloud-provider-payment8001微服务提供者支付Module模块建表SQL测试 IDEA新建project工作空间 微服务cloud整体聚合父工程Project 写pom文件 <?xml version"1.0" encoding"UTF-8"?><project xmlns"htt…

html画动态桃心

html画动态桃心 效果图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html><head><meta http-equiv"Content-Type" content"text/html; charsetwindows-1252"><title></title><style>* {padding: 0;margin…