最快速理解Vuex的方法
对于初学者,学vue简单,但是当第一次遇到Vuex概念的时候,理解难度往往骤然陡峭,会让人感到挫败感,挫败感来自于大多数教程文章用了大量篇幅来介绍Vuex较为复杂,却看完感觉没什么作用(不知道如何运用)的实现模式,本文就是要简而化之,让你秒懂。
本质
Vuex 术语定义叫做『全局状态管理』,其实质就是一个全局变量,可以供不同组件间调用,更新,自动通知。
当然在具体实现的时候,这个全局变量其实是一个全局对象:this.$store,
所以记住这个store对象,它就是vuex。
来龙去脉
facebook以前在搞他的那个网页app的时候,尤其是在做消息模块的时候,各种全局通知和聊天信息,组件间互相通信非常混乱,老出bug,于是他们就发明了一种解决这个问题的设计模式,叫做 FLUX。
这个设计模式是按照怎样的原则来解决通信混乱的问题呢?
1. 单一数据源(Single Source of Truth)
也就是说,store是一个唯一全局变量(对象),不能搞多个,搞多个就乱了。
2. 数据只读(Data is Read-Only)
这个只读不是说完全不让读,而是不能让 store外部直接操作数据,必须通过store内部方法(mutations)来操作数据。
3. 数据更新必须是同步的(Mutations Are Synchronous)
异步数据会很混乱,必须是同步操作模式。
为什么是这3个原则,你不用管,反正facebook反复实验,按照这三个原则设计,问题就搞定了。
facebook 按照FLUX设计模式,开发了大名鼎鼎的Redux库,React必备搭配。Vue看见此需求群众呼声很高,也配套了一个,也就是Vuex。
所以,Redux和Vuex都是对Flux这种设计模式的实现,别混为一谈。
store的内部
store 这个对象,肯定是挂载Vue上面的,就是按照下面这种方式挂:
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
},
actions: {
},
mutations: {
},
getters: {
},
modules: {
}
})
export default store
我们看到有这些 state,actions,mutations,modules这些属性, 为啥一个实质是变量的对象搞这么复杂,这其实和Flux设计模式有关系,它的本质就是:「我的事情我自己来,你们(组件)别直接操作我,告诉我就行,我自己来」。
下面一个一个讲:
state
state,这个所谓的状态,其实就是数据,全局的数据。
你在一个vue组件里,这样写,就可以获取这个数据:
computed: {
count () {
return this.$store.state.count
}
}
这个count就是state下面定义的一个数据,怎么定义的呢:
const store = new Vuex.Store({
state: {
count: 0
}
})
在那个挂载store对象的文件里,这样定义,非常符合直觉。 你这边写0,上面那边就读出0,你这边改成2了,上面就自动变成2,监听是默认的。
mutations
接着上面讲,你怎么把count改成2呢?
this.$store.state.count = 2
这样是不行的,前面讲过,你不要直接动store的数据,你需要告诉它,让他自己来处理。
所以store自己先得有个处理方法,这就是mutations:
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
})
这个方法就是increment,很符合直觉。
你在组件那里要做就是通知store,激活这个increment,怎么写呢:
this.$store.commit('increment')
注意,讲到这里,单词越来越多了,英语不好的同学需要记住对应关系,commit就是触发一个事件,通知store执行mutations下的某个方法。
getters
Vue 组件下面有个computed属性,一个组件自己用没问题,如果多个组件下都想使用一个共有的computed属性,那么这就是 store里面的getters。
唉,英语不好真伤心啊,起那么多名字其实是一个东西。
const store = new Vuex.Store({
state: {
todos: [
{ id: 1, text: '...', done: true },
{ id: 2, text: '...', done: false }
]
},
getters: {
doneTodos: state => {
return state.todos.filter(todo => todo.done)
}
}
})
看到没,上面getters动态属性doneTodos,就是拿state静态属性todos放进一个函数算了一遍。
actions
actions很简单,就是异步的mutations,咦?不对啊,前面我们讲flux三原则的时候,说过数据更新必须是同步的,这个还是英文的问题,Mutations Are Synchronous,说的是mutation,但是有时候我们需要异步去请求数据,这个时候就需要actions。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
},
actions: {
increment:function ({ commit }) {
axios.get('/add').then((response) => {
commit('increment')
}, (err) => {
console.log(err)
})
}
})
怎么触发actions里的increment呢?
this.$store.dispatch('increment')
我的天,又多了一个单词:dispatch, 知道为啥新手会觉得困难了吧?
官方文档给的那个示例其实不是很好,官方只是说action必须commit,但理解actions的关键在于它的使用场景是异步,因为flux的实质是同步,所以异步拿到数据后,必须通过mutation去更新数据,所以必须commit;
Modules
很多组件都共用store里面state来存数据,组件多了,时间久了,不利于管理。 于是就有这个modules模块
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`'s state
store.state.b // -> `moduleB`'s state
主要观察
modules: {
a: moduleA,
b: moduleB
}
在调用的时候,就可以分别调用
store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state
小结
看完这篇文章,你再去看官方文档,应该没问题了,但是如果我把官方文档的例子和其他信息全搬过来,你肯定会晕。
vuex很简单,难就难在那几个设计原则你不知道,还有就是单词有点多,记不过来。
看完文档后,你实验几次就知道怎么运用了。