为何会有 Vuex 这个东西 ?
现代前端框架主要解决的是 事件 -> 状态 -> UI 将传统前端在两个过程的代码剥离出来,变得更加容易维护;javascript
vue的声明式渲染,解决了 状态 和 UI 的同步问题,从而使咱们不须要因为状态发生改变去写大量的命令式改变 dom 的代码。html
而相似于 vuex 这类状态管理的库,则解决了 事件 -> 状态 这个过程的维护问题。这类库所作的事情就是管理从 事件源映射到状态变化 这个过程(将这个映射过程从视图组件中剥离出来,组织好这一部分的代码,在组件外部进行状态的管理)前端
具体表现就是一个全局的数据中心 store 配置,每一个组件进行更新的时候就通知数据中心,数据中心改变后,再去触发每一个调用它的组件进行更新(这种更新是响应式的);几个核心概念就是 mutations
里的方法能够直接 mutate
store 中的状态,而且 mutation
过程必须同步的,须要经过 commit
去触发;而 actions
则容许异步的操做,经过 commit
去触发 mutation
,达到间接修改 store
的目的,action
自己须要经过 disptch
去触发。vue
Vuex与全局对象的区别
其实,vuex
与全局对象有必定的共同之处,那就是状态会被全局共享,不管是嵌套多少组件…java
每个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有如下两点不一样:git
- Vuex 的状态存储是 响应式 的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地获得 **高效更新 **。
- 你不能直接改变 store 中的状态。改变 store 中的状态的惟一途径就是显式地提交 (commit) mutation。这样使得咱们能够方便地跟踪每个状态的变化,从而让咱们可以实现一些工具帮助咱们更好地了解咱们的应用。
Vuex常见的应用场景
管理状态与共享状态程序员
应用简单时,可使用 prop
与 event
来完成 父子组件 的通讯。使用 global event bus(event bus)
来实现 简单的非父子组件之间的跨组件 通讯。但对于 **多层级组件嵌套 **等较为复杂的场景,使用 vuex
能更好地应对。(使用 event bus 的缺点是当状态较复杂,调用组件很是多,要挨个依次通知全部组件更新;每一个组件对这个组件进行的状态更新都要通知监听该事件的全部组件;这样会变得很是复杂)github
vuex
状态管理模型,拥有一个统一的数据中心Store,Store用来维护状态数据;每一个组件进行更新的时候就通知数据中心,数据中心改变后,再去触发每个调用它的组件进行更新(至关于由数据中心来统筹状态变化以及状态变化的分发,而不是由每一个vue
组件直接去操做state)vue-router

vuex
是经过将 state
做为数据中心,各个组件 共享 state 来实现跨组件通讯的, 此时的数据彻底独立于组件。(点击不一样模块的操做,再也不须要去发送乱七八糟的事件, 只是去调用事件中内心的 mutation
动做, 从而实现模块间共享状态的功能)vuex
须要构建一个中大型单页应用时,极可能会考虑如何更好地 在组件外部 管理状态
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-demo
原文出处:https://www.cnblogs.com/rencoo/p/12049831.html