[vue]初探vue生态核心插件Vuex
为什么会有 Vuex 这个东西 ?
现代前端框架主要解决的是 事件 -> 状态 -> UI 将传统前端在两个过程的代码剥离出来,变得更加容易维护;
vue的声明式渲染,解决了 状态 和 UI 的同步问题,从而使我们不需要由于状态发生改变去写大量的命令式改变 dom 的代码。
而类似于 vuex 这类状态管理的库,则解决了 事件 -> 状态 这个过程的维护问题。这类库所做的事情就是管理从 事件源映射到状态变化 这个过程(将这个映射过程从视图组件中剥离出来,组织好这一部分的代码,在组件外部进行状态的管理)
具体表现就是一个全局的数据中心 store 配置,每个组件进行更新的时候就通知数据中心,数据中心改变后,再去触发每个调用它的组件进行更新(这种更新是响应式的);几个核心概念就是 mutations里的方法可以直接 mutatestore 中的状态,并且 mutation 过程必须同步的,需要通过 commit 去触发;而 actions 则允许异步的操作,通过 commit 去触发 mutation ,达到间接修改 store的目的,action 本身需要通过 disptch去触发。
Vuex与全局对象的区别
其实,vuex 与全局对象有一定的共同之处,那就是状态会被全局共享,无论是嵌套多少组件…
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
- Vuex 的状态存储是 响应式 的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到 高效更新。
- 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
Vuex常见的应用场景
管理状态与共享状态
应用简单时,可以使用 prop与 event 来完成 父子组件 的通信。使用 global event bus(event bus)来实现 简单的非父子组件之间的跨组件 通信。但对于 多层级组件嵌套 等较为复杂的场景,使用 vuex 能更好地应对。(使用 event bus 的缺点是当状态较复杂,调用组件非常多,要挨个依次通知所有组件更新;每个组件对这个组件进行的状态更新都要通知监听该事件的所有组件;这样会变得非常复杂)(你通知我, 我通知你, 你通知他, 他通知我 ... 大家之间是直接相互作用的)
vuex 状态管理模型,拥有一个统一的数据中心Store,Store用来维护状态数据;每个组件进行更新的时候就通知数据中心,数据中心改变后,再去统一触发每一个调用它的组件进行更新(相当于由数据中心来统筹状态变化以及状态变化的分发,而不是由每个vue组件直接去操作state) (有点类似于中介者模式, 大家把所有各种类型的信息都反馈给中介, 然后再由中介分发给订阅了某个类型信息的用户)
图解
vuex 是通过将 state 作为数据中心,各个组件 共享 state 来实现跨组件通信的, 此时的数据完全独立于组件。(点击不同模块的操作,不再需要去发送乱七八糟的事件, 只是去调用事件中心里的 mutation 动作, 从而实现模块间共享状态的功能)
需要构建一个中大型单页应用时,很可能会考虑如何更好地 在组件外部 管理状态
vuex更多地用于解决 跨组件通信 (多层嵌套组件之间的通信问题)以及作为 数据中心集中式存储数据 (管理应用中错综复杂的状态关系)
vuex 作为数据存储中心
vuex的 state在单页应用的开发中本身具有一个 数据库 的作用,可以将组件用到的数据存储在 state中,并在 actions中封装数据读写的逻辑。目前主要有两种数据会使用 vuex进行管理
- 组件之间 全局共享 的数据
- 通过后端异步请求的数据
实际项目开发中更多的是用到第二种,即把通过后端异步请求的数据都纳入 vuex 状态管理,在 actions 中封装数据的增删改查等逻辑,这样可以在一定程度上对前端的逻辑代码进行分层,使组件中的代码更多地关注页面交互与数据渲染等 视图层 的逻辑,而异步请求与状态数据的持久化等则交由 vuex 管理
一般全局数据,会使用到 vuex 来管理。比如 用户数据,系统数据 等,这些数据很多组件中都会使用,我们当然可以每次使用的时候都去请求,但是出于程序员的“洁癖”、“抠”等等优点,还是希望一次请求,到处使用。
这时候很自然的想到存储在 localStorage 中,但是有个问题是,这些数据可能会变,如果没能及时 同步 的话,就会用到不正确的数据,即使做了数据同步,但是 localStorage 中的数据不是响应式的,不能自动更新使用到这些数据的地方。这时候就想要开始使用 vuex了。
Vuex代码的组织方式
与 vue-router 类似,有非模块化写法与模块化写法(其实无论何种写法本质上是一样的,目的就是导出一份 router或者 store 的配置数据)
以管理 count 与 用户信息 userinfo 为例,介绍 vuex代码的组织方式
核心概念 state,getter,mutation,action,module
vuex 需要遵守的规则
应用层级的状态应该集中到 单个 store 对象中
mutation是直接操作state的方法(唯一能改变状态的方法),过程要求必须同步
action 通过commit去触发mutation,从而间接修改状态,优点是允许异步逻辑,
非模块化写法
// 1.安装 vuex
// 2.在入口文件中引入
// main.js
import Vuex from 'vuex'
// 3.Vue使用 vuex 插件
Vue.use(Vuex)
// 4.生成数据管理中心 store
const store = new Vuex.Store({
state: {
userinfo: null, // 需要给定初始值
count: 0
},
// 直接通过mutation方法来mutate操作state; 只能以同步的方式; mutation方法需要通过commit来触发
mutations: {
userinfo: function (state, payload) {
state.userinfo = options
localStorage.userinfo = JSON.stringify(state.userinfo)
},
increment: function (state, payload) {
state.count += payload.amount
}
},
// 通过commit触发mutations里的mutation方法, 以此间接修改 state; 允许异步操作;action方法需要通过dispatch来触发
actions: {
increment: function (context, payload) {
context.commit('increment', payload)
},
incrementAsync: function (context) {
// 异步请求数据
setTimeout(() => {
var amount = 10; // 模拟异步请求得到数据
context.commit('increment', { amount })
}, 1000)
},
async userinfo (context) {
let response = await getUserInfo() // 异步请求后端数据 方法需要 import
if (response.ok) {
let json = await response.json()
context.commit('userinfo', json)
}
}
},
getters: {// 处理、过滤数据
}
})
// 5.通过 store 配置参数注入状态管理,从而任何组件可通过 this.$store 访问状态中心
new Vue({
el: '#app',
store, // (*)
render: function (h) {
return h(App)
}
})
模块化写法
// 1.安装vuex
// 2.引入
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
// import ...
// 3.Vue使用 vuex 插件
Vue.use(Vuex)
// 4.分模块生成数据管理中心
// 配置 userinfo 状态模块 (还能再单独拆出一个文件,然后import进来)
const moduleA = {
state: {
userinfo: null // 需要初始化响应式数据
},
mutations: {
userinfo: function (state, options) {
state.userinfo = options
localstorage.userinfo = JSON.stringify(state.userinfo)
}
},
actions: {
async userinfo (context) {
async userinfo (context) {
let response = await response.json()
if (response.ok) {
let json = await response.json()
context.commit('userinfo', json)
}
}
},
getters: {// 处理、过滤数据
}
}
}
// 配置 count 状态模块 (还能再单独拆出一个文件,然后import进来)
const moduleB = {
state: {
count: 1,
},
mutations: {
increment:function (state, payload) {
state.count += payload
},
},
actions: {
increment: function (context, payload) {
context.comit('increment', payload)
},
incrementAsync: function (context) {
// 异步请求数据
setTimeout(() => {
var amount = 10; // 模拟异步请求得到数据
context.commit('increment', { amount })
}, 1000)
},
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
// 5.导出一份 store 的配置
export default new Vuex.Store({
modules: { // 这里与非模块化写法有点不一样;原来整个对象是一份配置...
a: moduleA,
b: moduleB,
}
})
// store.state.a // -> moduleA 的状态
// store.state.b // -> moduleB 的状态
// 6.在根脚本 main.js 中引入 store 配置
import store from './store'
...
// 并通过 store 配置参数注入状态管理,从而任何组件可通过 this.$store 访问状态中心
new Vue({
el: '#app',
router,
store,
render: function (h) {
return h(App);
}
});
在不同组件中使用或操作状态
// 根组件
// App.vue
// 在生命周期中触发全局共享数据的获取
...
mounted () {
if (!this.$store.state.userinfo) { // this.$store.state.a.userinfo 模块化写法的话
this.$store.dispatch('userinfo')
}
}
// 使用 state 的数据
computed: {
userinfo () {
return this.$store.state.userinfo
// return this.$store.state.a.userinfo // 模块化写法的话
},
count () {
return this.$store.state.count
// return this.$store.state.b.count // 模块化写法的话
}
}
// 子组件
// NavBar.vue
...
// 改变 state 的数据
methods: {
// 使用 commit 触发 mutations 中的 mutation 方法,直接修改 state 中的数据
addOne () {
this.$store.commit('increment', { amount: this.price })
},
// 使用 dispatch 触发 actions 中的 action 方法;异步修改 state 中的数据
addTenAsync () {
this.$store.dispatch('incrementAsync')
}
}
// 使用 state 的数据
computed: {
userinfo () {
return this.$store.state.userinfo
// return this.$store.state.a.userinfo // 模块化写法的话
}
}
// 路由页面组件
// Manage.vue
...
// 改变 state 的数据
methods: {
addTwo () {
this.$store.commit('increment', { amount: this.price })
}
}
// 使用 state 的数据
computed: {
count () {
return this.$store.state.count
// return this.$store.state.b.count // 模块化写法的话
}
},
总之,使用了 vuex 来管理状态,点击不同模块的操作,不再需要去发送乱七八糟的事件, 只是去调用事件中心里的 mutation 动作, 从而实现模块间共享状态的功能;修改一处,全局共享(无论是组件还是路由页面组件都能同步)
最后,再看看 vuex 官网的这张说明图,是不是更加清晰了呢!
虚线绿框里即vuex做的事
-项目地址- vuex-demo
[vue]初探vue生态核心插件Vuex的更多相关文章
- vue从入门到精通之【vuex】(七)
vue从入门到精通之[vuex](七) vuex一个公用的大仓库,Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架. Vuex 实现了一个单向数据流,在全局拥有一个 state 存放数据, ...
- vue.js 开发生态总结
---title: Vue 1.0 的技术栈date: 2016-09-26 00:48:50tags:category:--- ## vuejs概述 Vue.js是用于构建交互式的Web界面的库.它 ...
- 【vue】vue +element 搭建项目,vuex中的store使用
概述: 每一个 Vuex 应用的核心就是 store(仓库).“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state).Vuex 和单纯的全局对象有以下两点不同: Vuex 的 ...
- day 87 Vue学习六之axios、vuex、脚手架中组件传值
本节目录 一 axios的使用 二 vuex的使用 三 组件传值 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 axios的使用 Axios 是一个基于 promise 的 HT ...
- [译]怎样在Vue.js中使用jquery插件
原文:http://gambardella.info/2016/09/05/guide-how-to-use-vue-js-with-jquery-plugins 使用Vue真的太棒了,但是也有可能使 ...
- Vue 爬坑之路—— 使用 Vuex + axios 发送请求
Vue 原本有一个官方推荐的 ajax 插件 vue-resource,但是自从 Vue 更新到 2.0 之后,官方就不再更新 vue-resource 目前主流的 Vue 项目,都选择 axios ...
- day 84 Vue学习六之axios、vuex、脚手架中组件传值
Vue学习六之axios.vuex.脚手架中组件传值 本节目录 一 axios的使用 二 vuex的使用 三 组件传值 四 xxx 五 xxx 六 xxx 七 xxx 八 xxx 一 axios的 ...
- 【Vue】Vue学习(四)-状态管理中心Vuex的简单使用
一.vuex的简介 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.Vuex背后的基本思想,就是前面所说的单向数据流.图4就是Vuex实现单向数据流的示意图. Store ...
- vue初探
vue初探 很多同学一定都听过MVVM.组件.数据绑定之类的专业术语,而vue框架正是这样的一种框架.vue的作用是:通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件. 第一部分:vue介 ...
随机推荐
- Sequelize小记
http://docs.sequelizejs.com/ 官方英文 Object-Relational Mapping 增 Model.create({field1:'a', field2:'b' ...
- Ubuntu 16.04 安装Docker
1 更改apt源,更改前先对sources.list文件进行备分 ccskun@test:~$ sudo cp /etc/apt/sources.list /etc/apt/sources.list. ...
- 2019-10-23:渗透测试,基础学习,DVWA,Medium和Hight级别sql注入
VWA的Medium和Hight级别sql注入 一,Medium级 服务端代码 <?php if( isset( $_POST[ 'Submit' ] ) ) { // Get inp ...
- 高德JS依赖分析工程及关键原理
一.背景 高德 App 进行 Bundle 化后,由于业务的复杂性,Bundle 的数量非常多.而这带来了一个新的问题——Bundle 之间的依赖关系错综复杂,需要进行管控,使 Bundle 之间的依 ...
- 【Luogu P1967】货车运输
Luogu P1967 题目大意:给定一张图和q个询问,询问x节点和y节点的路径之间最小边权最大可以是多少. 可以发现对于一条边\(E(x,y)\),如果x到y有另一条路径且最小边权大于\(E(x,y ...
- [CSS七分钟系列]都1902年了,还不知道用margin:auto给flex容器内元素分组?
最近看到几篇博文讲解margin:auto在flex容器中的使用,可惜的是大多讲解都浮于页面表现,没深究其中的作用机理,本文在此浅薄对其表现机理做简单探讨. 引子 日常业务迭代过程中,flex已经是前 ...
- java中的运算,+-* /% | ^ &
java中运算都是操作符号,那么整形默认为int,双精度默认为都double 整数 看案例: 无法编译通过:操作默认为int,接受结果为int,所以这个地方编译无法通过,所以需要强制类型转换 再看案例 ...
- day 18 random模块 时间模块 sys模块 os模块
import random 利用random模块可以进行从一个列表或者数字范围之间随机取出一个数字 # 取随机小数 : 数学计算 print(random.random()) # 取0-1之间的小数 ...
- JDK1.8新特性(一):stream
一.什么是stream? 1.概述 Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据. 这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管 ...
- 更强、更稳、更高效:解读 etcd 技术升级的三驾马车
点击下载<不一样的 双11 技术:阿里巴巴经济体云原生实践> 本文节选自<不一样的 双11 技术:阿里巴巴经济体云原生实践>一书,点击上方图片即可下载! 作者 | 陈星宇(宇慕 ...