Vuex极速入门
01、什么是Vuex?
1.1、为什么需要状态管理?
在复杂的系统中,我们会把系统按照业务逻辑拆分为多个层次、多个模块,采用组件式的开发方式。而此时不同模块、父子模块之间的通信就成了一个问题。
为了解决这个问题,就有了状态管理,核心概念就是把大家共享的状态(数据)抽出来,放到一个全局共享的仓库里,按照一定约定统一管理,让状态的变化可预测。这就有两个关键点:
- 统一存储:共享的状态统一存储,全局共享。
- 可预测:共享的状态不可随意修改,需要按照约定的规则修改,才能监测状态变更、通知更新。
1.2、Vuex简介
Vuex 就是面向Vue的状态管理组件,采用集中式存储+管理应用的所有共享状态。Vuex只能在Vue中使用,深度使用了Vue的能力,如用Vue来实现state
的响应式特性。
Vue2.*
版本 对应Vuex3.*
版本,Vuex3.* 中文文档Vue3.*
版本 对应Vuex4.*
版本,Vuex4.* 中文文档
简单来说,就是Vuex有一个全局公共的store
(类似Vue里的data
),作为公共数据仓库,保存了大家共享的状态(数据)。这个数据仓库store
实现了数据响应、自动通知更新,这样就很容易实现了各个组件间的数据通信了。
其实,对于简单的应用不一定需要Vuex,不过Vuex文件并不大(gzip压缩后10K左右)。
Vuex主要特点就是:单向数据流+单一数据源。
- state:存储数据仓库,类似Vue的
data
,也是响应式的,变更后会自动通知View。 - views:组件视图,就是使用
state
的Vue组件。 - actions:更新state状态,为了规范管理,state不能直接修改,必须通过
action
进行提交。Vuex中分为同步Mutation、和异步Action。
02、安装使用
- 通过
<script>
标签直接引用vuex.js
:
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/vuex@3/dist/vuex.js"></script>
// 注册插件
Vue.use(Vuex);
- 通过
vue-cli
脚手架搭建vue的开发框架,集成了vuex组件。 - 注册插件:
Vue.use(Vuex)
调试已经被集成在了Vue的调试工具Devtools中了。
03、Vuex3入门
3.1、Vuex选项&实例
Store构造器选项 | 描述 |
---|---|
state | Vuex store 实例的根 state 对象 |
mutations | 注册 mutation,就是修改数据的方法,参数为state 。不支持异步,通过store.commit(name) 调用 |
actions | 注册 action,参数为context ,同store 实例,但不是她。支持异步,通过store.dispatch(name) 调用 |
getters | 注册 getter,{ [key: string]: Function } ,参数为state ,定义、使用同计算属性 |
modules | 子模块的对象,分割管理store,{ key(moduleName) : {state, namespaced?, mutations?, actions? ... }} |
strict | 是否严格模式,默认false,true=严格模式下,任何 mutation 处理函数以外修改state 都会抛出错误。 |
store实例属性 | 描述 |
---|---|
state | 数据源state 根对象 |
getters | 所有注册的getter |
store 实例方法 | |
commit(name, arg?, options?) | 提交 mutation 执行申请,name 为mutation 注册的方法名 |
dispatch(name, arg?, options?) | 提交 action 执行申请,name 为action 注册的方法名 |
replaceState(state: Object) | 替换 store 的根状态,用于合并状态,如加载持久化的state 数据。 |
watch(fn, callback) | 响应式地侦听 fn 的返回值,当值改变时调用回调函数 |
subscribe(handler, option?) | 订阅 store 的 mutation,每一个mutation执行完调用 |
subscribeAction(handler, option?) | 订阅 store 的 action |
registerModule(path, module) | 注册一个动态模块 |
unregisterModule(path) | 卸载一个动态模块 |
hasModule(path) | 检查模块是否以注册 |
hotUpdate(newOptions: Object) | 热替换新的 action 和 mutation |
const store = new Vuex.Store({
strict:false,
state: { //定义数据结构-数据仓库
points: 1000,
user: { id: '001', name: 'sam' }
},
mutations: { //修改数据的方法
setUser(state, obj) {
state.user.id = obj.uid;
state.user.name = obj.uname;
},
},
actions: { //修改数据的方法-异步
set(context, obj) { context.commit('setUser', obj) }
},
getters: { //获取数据的计算属性
userExist(state) { return state.user.id != ''; }
}
})
//提交数据修改
store.commit('setUser',{uid:'007',uname:'zhangsan'});
console.log(store.state.user); //id : "007" name : "zhangsan"
console.log(store.getters.userExist); //true
3.2、Vuex核心流程
Vuex核心概念:
- Store 单一状态树:一个应用程序中只有一个Store实例(单例模式),Store包含了
state
、actions
、mutations
、getter
、modules
。一般会在根Vue注册store
实例,这样组件内所有地方都可以this.$store
访问了。 - State 数据源:实现了响应式监听,可用
mapState
辅助函数包装为计算属性访问。 - Getter 访问属性:返回对
state
状态数据进行加工后的结果,类似Vue中的计算属性、过滤器,区别就是这是全局共享的。 - Mutation 修改数据:Vuex中用于修改状态数据的主要方式,是唯一修改
state
数据的合理途径了。通过store.commit()
调用mutation
。(mutation /mjuːˈteɪʃ(ə)n/ 改变) - Action 异步操作:类似Vue的
methods
,支持异步操作。通过store.dispatch()
调用,实际修改数据也是要调用mutation
的。Action 可用来发起异步ajax请求获取处理 state的数据,这是和mutation最大的不同了。 - Module 模块:当Store很复杂时,用Module拆分为多个模块管理,每个模块里有自己的
state
、actions
、mutations
、getter
、modules
。
基本流程:
❶ 定义数据 state,和data一样,预先定义好数据结构,以及数据更新的mutation
方法。
❷ 使用数据 state
- 在根组件注入
store
实例,组件内所有地方(包括后代组件)都可以this.$store
访问了。 - 通过计算属性
computed
包装所需的state
数据。如果state
数据需要双向绑定到表单元素,则需要用计算属性实现get、set来代理实现。 - 通过方法
methods
包装数据的更新store.mutation
。 - 在
View
上绑定使用,可以绑定包装后的计算属性、方法,也可以直接绑定注入的$store
。
❸ 触发更新,根据业务需要更新state数据。
- store.commit(name, arg?, options?)
- store.dispatch(name, arg?, options?)
❹ 正式修改state
数据,并触发 View 自动更新。
<div id="app">
<button @click="login">登录</button>
<p>用户:{{$store.state.user.name}}({{$store.state.user.id}})</p>
<p v-text="`用户:${$store.state.user.name}(${$store.state.user.id})`"></p>
</div>
<script>
// 注册插件
Vue.use(Vuex);
//申明全局store
const store = new Vuex.Store({
state: { user: { id: '', name: '' } },
mutations: { setUser(state, obj) { state.user.id = obj.uid; state.user.name = obj.uname; }, },
getters: { userExist(state) { return state.user.id != ''; } }
})
//根Vue
let app = new Vue({
el: '#app',
data: {},
store: store, //在根组件注入store实例,组件内所有地方都可以 this.$store 通过访问了
methods: {
login() { this.$store.commit('setUser',{ uid: '007', uname: 'zhangsan' }) }
}
})
</script>
3.3、创建Vuex()-购物车案例
- 注册插件:
Vue.use(Vuex)
- 创建全局共享的
Store
实例,并配置数据、方法。 - 注入
store
,在根Vue组件上注入store实例。 - 愉快的使用了。
<script>
// 注册插件
Vue.use(Vuex);
//申明全局store
const store = new Vuex.Store({
state: { cart: ['汽车01', '苹果', '梨子'] },
mutations: {
add(state, item) { state.cart.push(item); },
delete(state, index) { state.cart.splice(index,1) }
},
actions: { add(context, item) { context.commit('add', item) } },
getters: { cartTotal(state) { return state.cart.length; } }
})
</script>
<div id="app1">
<p>购物车({{this.$store.getters.cartTotal}})(直接绑定)</p>
<p>购物车({{cartTotal}}) <button @click="add">添加商品</button></p>
<cart-box></cart-box>
</div>
<template id="cardBoxTemplate"> <!--购物列表模板-->
<ul>
<li v-for="(item,index) in cartList">{{item}} <button v-on:click="deleteItem(index)">删除</button></li>
</ul>
</template>
<script>
let app1 = new Vue({
el: "#app1",
data: {},
store: store, //在根组件注入store实例,组件内所有地方都可以 this.$store 访问了
computed: {
cartTotal: function () { return this.$store.getters.cartTotal; }
},
methods: { add: function (item) { this.$store.dispatch('add', "西瓜") } },
components: { //购物车组件
'cart-box': {
computed: { cartList() { return this.$store.state.cart; } },
template: '#cardBoxTemplate',
methods: { deleteItem: function (index) { this.$store.commit("delete", index); } }
}
}
})
</script>
3.4、...mapState语法糖
mpaState
是state
的一种Vuex提供的 “语法糖”,主要作用是简化代码。比如当state
有多个状态属性,在组件中都要用就得一个一个包装,代码冗余。这时,mapState
就可以简化这个重复、无聊的代码了。
<script>
let app1 = new Vue({
el: "#app1",
data: {},
store: store,
computed: { //做一个简单包装,使用时更方便
card() { return $store.state.card; },
user() { return $store.state.user; }
},
computed: Vuex.mapState(['card', 'user']), //直接赋值,效果同上,简化了包装代理代码
computed: {
cartTotal: function () { return this.$store.getters.cartTotal; },
//展开运算符展开
...Vuex.mapState({
'cart': 'cart', //计算属性名称:state状态名称
currentUserId: 'user',
}),
...Vuex.mapState(['cart', 'user']) //更简洁的写法
},
})
</script>
- mpaState() 是Vuex提供一个辅助函数,帮助生成计算属性。返回的是一个对象(结构同计算属性
computed
)。
mapState(namespace?: string, map: Array<string> | Object<string | function>): Object
- ...mapState,三个点
...
是ES6的展开运算符,把对象展开混入当前环境。
其他还有 mapGetters、mapActions、mapMutations 都是类似作用和用法。
3.5、Module模块化
当共享的数据和操作太多时,就需要分模块管理了,如下模块示例。
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 的状态
每个模块 module 都包含完整的store
结构。
module定义结构:
{ key(moduleName) : {state, namespaced?, mutations?, actions?, getters? modules? }}
- key:就是模块的名称,也是模块的命名空间。
- value,就是一个和
store
结构相同的对象,存放模块的store
信息。模块里方法的参数state
、context
都是命名空间内的局部对象。
模块化的项目结构:
├── index.html
├── main.js
├── api
│ └── ... # 抽取出API请求
├── components
│ ├── App.vue
│ └── ...
└── store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
└── modules
├── cart.js # 购物车模块
└── products.js # 产品模块
04、Vuex4区别
几乎所有的 Vuex 4
API 都与 Vuex 3
保持不变,有少量差异。
- 创建方式不同,Vuex4 使用
createStore({})
函数创建store
对象,之前的方式依然支持。 - 安装方式,
app.use(store)
,已经注入了store
实例,不用再注册store
实例了。 - 打包产物已经与 Vue 3 配套。
- 新特性:
useStore
组合式函数。//TODO
05、一些问题
Vuex的持久化?
如果用户刷新页面,导致页面的各种实例重新初始化,之前的全局状态就会丢失。解决方法就是把state
数据仓库存起来,当刷新页面的时候读取出来,如果关闭页面就不用管了。
- 持久化
state
:在页面刷新时的beforeunload
事件中保存state
到sessionStorage
里。sessionStorage
刷新页面不会丢失,关闭才清除。 - 加载
state
:Vuecreate
中加载持久化的state,并清除持久化的state
数据。
created: function () {
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('vstore', JSON.stringify(this.$store.state));
});
try {
const vstore = sessionStorage.getItem('vstore')
if (vstore)
this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(vstore)));
}
catch (ex) { console.log(ex) }
sessionStorage.removeItem('vstore');
}
️版权申明:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!原文编辑地址-语雀
Vuex极速入门的更多相关文章
- [转]Nginx基本功能极速入门
原文链接:Nginx基本功能极速入门 | 叉叉哥的BLOG 本文主要介绍一些Nginx的最基本功能以及简单配置,但不包括Nginx的安装部署以及实现原理.废话不多,直接开始. 1.静态HTTP服务器 ...
- 《Python黑客编程之极速入门》正式开课
玄魂 玄魂工作室 今天 之前开启了一个<Python黑客编程>的系列,后来中断了,内容当时设置的比较宽,不太适合入门.现在将其拆分成两个系列<Python黑客编程之极速入门>和 ...
- 1 小时 SQL 极速入门(三)——分析函数
1 小时 SQL 极速入门 前面两篇我们从 SQL 的最基础语法讲起,到表联结多表查询. 大家可以点击链接查看 1 小时 SQL 极速入门(一) 1 小时 SQL 极速入门(二) 今天我们讲一些在做报 ...
- Go 语言极速入门
本系列文章主要是记录<Go 语言实战>和<Google 资深工程师深度讲解 Go 语言>的学习笔记. Go 语言极速入门1 - 环境搭建与最简姿势Go 语言极速入门2 - 基础 ...
- Vuex 2 入门与提高。
从计数器开始 让我们从一个简单的计数器,开始进入Vuex 的世界: 计数器应用的数据模型很简单:使用一个counter属性来表示计数器的 当前值就够了. 在Vue实例的created钩子 中,应用启动 ...
- Vuex的入门教程
前言 在 Vue.js 的项目中,如果项目结构简单, 父子组件之间的数据传递可以使用 props 或者 $emit 等方式,详细点击这篇文章查看. 但是如果是大型项目,很多时候都需要在子组件之间传递 ...
- 多本Python极速入门最佳书籍,不可错过的Python学习资料!
Python作为现在很热门的一门编程语言,介于Python的友好,许多的初学者都将其作为首选,为了帮助大家更好的学习Python,我筛选了2年内优秀的python书籍,个别经典的书籍扩展到5年内. ...
- vuex 基本入门和使用(三)-关于 mutation
vuex 基本入门和使用(三)-关于 mutation vuex 版本为^2.3.1,按照我自己的理解来整理vuex. 关于 mutation 这里应该很好理解. 更改 Vuex 的 store 中的 ...
- Knative 初体验:CICD 极速入门
Knative 社区很早就在讨论用 Tekton 替换 Build 模块的相关事宜.Knative Build 官方已经正式说明不再建议使用 Knative Build 了. 如果你知道 Knativ ...
- 60 分钟极速入门 PyTorch
2017 年初,Facebook 在机器学习和科学计算工具 Torch 的基础上,针对 Python 语言发布了一个全新的机器学习工具包 PyTorch. 因其在灵活性.易用性.速度方面的优秀表现,经 ...
随机推荐
- 示例:Service连接应用程序
整体思路: 1.创建pod 2.创建关联上一步pod的service 3.使用不同的方式配置service从而能够在集群内部访问 4.使用ssl方式加密访问service 5.配置service为no ...
- Alertmanager配置概述
Alertmanager主要负责对Prometheus产生的告警进行统一处理,因此在Alertmanager配置中一般会包含以下几个主要部分: 全局配置(global):用于定义一些全局的公共参数,如 ...
- td-agent的v2,v3,v4版本区别
官方地址:https://docs.fluentd.org/quickstart/td-agent-v2-vs-v3-vs-v4
- .Net 7 C#11 原始字符串
.Net7 的到来的同时,也带来了 C# 11,而令我最期待的就是 C# 11 的 原始字符串了,当我知道这个的时候,简直比过年还要开心. 非原始字符串 首先我们看看现在写字符串的方式 var str ...
- C++自学笔记 头文件 (header file)关于 #include 和.h
头文件 在C++中定义Definition一个类的时候 要用分别的.h和.cpp文件去定义这个类 .h和.cpp成对出现 类的声明declaration和函数原型放在头文件里(.h) 定义这些函数的结 ...
- Springboot 之 Filter 实现 Gzip 压缩超大 json 对象
简介 在项目中,存在传递超大 json 数据的场景.直接传输超大 json 数据的话,有以下两个弊端 占用网络带宽,而有些云产品就是按照带宽来计费的,间接浪费了钱 传输数据大导致网络传输耗时较长 为了 ...
- springboot+thymeleaf中前台页面展示中、将不同的数字替换成不同的字符串。使用条件运算符
主要用到的知识就是thyme leaf中的条件运算符 表达式:(condition)?:then:else 当条件condition成立时返回then.否则返回else 具体代码:<td th: ...
- curl 下载地址中有特殊字符解决方案
curl 下载地址中有特殊字符解决方案 情况 使用 curl 下载 地址中带有 特殊字符的时候 比如下面这个地址.实际访问地址不正确,参数丢失问题 curl -o kspf.jpeg https:// ...
- 快速创建软件安装包-ClickOnce
大家好,我是沙漠尽头的狼. .NET是免费,跨平台,开源,用于构建所有应用的开发人员平台. 今天介绍使用ClickOnce制作软件安装包,首先我们先了解什么是ClickOne. 1. 什么是Click ...
- Angular SSR 探究
一般来说,普通的 Angular 应用是在 浏览器 中运行,在 DOM 中对页面进行渲染,并与用户进行交互.而 Angular Universal 是在 服务端 进行渲染(Server-Side Re ...