WW(是什么、为什么)
什么是vuex? 如果你学过react,那么你就更容易理解vuex,因为vuex相当于react中的redux,它是用于管理数据的工具。我们看一看官网的介绍:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
为什么要使用vuex? 因为如果不用vuex,我们也可以控制组件之间的通信,但是会非常的难以管理,而通过vuex我们可以更为方便的控制数据在组件之间的通信。 尤其是对于父组件向子组件传递数据,我们可以通过props,而子组件向父组件传递数据,我们可以使用events up。 但是如果希望组件之间的通信(这往往也是最为需求的), 我们就很难处理,这是vuex就派上用场了。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 global event bus 就足够您所需了。但是,如果您需要构建是一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
VUEX核心
vuex的核心就是一个store(仓库),这个仓库中包含了所有的状态。 关键词: 状态 --- vue中使用了状态这个词,实际上就是数据,只是这个数据是响应式的, 当store中的状态发生变化时,依赖这个store的组件也会得到高效的更新,值得注意的是: 我们不能随意的改变这个状态,而必须通过特有的方式 --- 显式地提交(commit) mutations。这种方式的好处在于我们可以方便的管理状态的改变。
VUEX简单实例
在使用下面的实例过程中我们需要先安装vuex,通过npm的方式或者通过使用cdn的方式都是可以的。下面是一个最简单的的例子:
// 如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex) const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } } })
可以看到,我们再使用vue时,无论是vue,还是vue-router,或者是vuex,都需要创建一个实例来使用。
现在我们可以使用store.state.count的方式来访问状态对象、通过store.commit('increment')的方式触发状态变更 --- 这也是修改store中的状态的唯一方式,所以我们不能通过给store.state.count赋值的方式来修改仓库中的state,这样限制的好处在于我们可以更清晰、容易地来控制数据。
vuex核心概念之一 state
首先要理解的是vuex使用的是单一状态树,即vuex的状态管理处于一棵树,也许你的应用非常复杂,分为了很多不同的模块,但是每个应用也仅仅包含一个store实例, 我们可以将store分散到各个子模块中去。
那么我们如果读取到state呢? vuex的方式是将store注册到vue实例中(前提是使用vue.use(vuex)),然后才能获取到状态,
const app = new Vue({ el: '#app', // 把 store 对象提供给 “store” 选项,这可以把 store 的实例注入所有的子组件 store, components: { Counter }, template: ` <div class="app"> <counter></counter> </div> ` })
即创建了一个实例之后,我们将store注册进来,然后该 store 实例会注入到根组件下的所有子组件中,且子组件可以通过 this.$store访问到状态对象。
访问一个状态我们需要使用计算属性,但是如果我们需要访问到很多状态,那么每一个状态都通过计算属性得到就会非常麻烦,于是vuex提供了mapState。
vuex核心概念之二Getters
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤并计数:
computed: { doneTodosCount () { return this.$store.state.todos.filter(todo => todo.done).length } }
如果有多个组件需要用到此属性,我们要么复制这个函数,或者抽取到一个共享函数然后在多处导入它 —— 无论哪种方式都不是很理想。
Vuex 允许我们在 store 中定义『getters』(可以认为是 store 的计算属性)。Getters 接受 state 作为其第一个参数。
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) } } })
vuex核心概念之三mutations
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutations 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
const store = new Vuex.Store({ state: { count: 1 }, mutations: { increment (state) { // 变更状态 state.count++ } } })
然后通过store.commit('increment')就可以来更改state了。
提交载荷
我们使用mutations改变状态,同时在commit时我们可以传递参数,如:
mutations: { increment (state, n) { state.count += n } } store.commit('increment', 10)
但是这里只传入了一个参数,但是对于复杂的页面,我们往往需要传入多个参数,那么传入一个对象是一个不错的选择,这就是payload。如下:
// ... mutations: { increment (state, payload) { state.count += payload.amount } } store.commit('increment', { amount: 10 })
其中传入的这个对象就是payload。
当然,在使用提交时,我们还可以换一种风格,即只传一个对象作为参数,把mutations中的方法作为对象的type的值,如下所示:
store.commit({ type: 'increment', amount: 10 })
并且handler是不变的。
值得注意的是: mutation必须是同步函数。
vuex核心概念之四actions
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。
下面就是一个简单的actions:
const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') } } })
可以看到action的提交时mutation而不是直接变更状态, 所以mutation是唯一可以变更状态的方法就是成立的了。
vuex核心概念之五modules
最开始我们说到了state是单一状态树,即整个应用使用一个状态树。 但是又提到了如果应用比较大时,我们的代码一般都是分模块的,那么这个状态树应当是分散的。
Vuex 允许我们将 store 分割到模块(module)。每个模块拥有自己的 state、mutation、action、getters、甚至是嵌套子模块——从上至下进行类似的分割:
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 的状态
项目结构
vuex并不会限制你的代码结构,但是它要求你必须遵守一定的规则:
-
应用层级的状态应该集中到单个 store 对象中。
-
提交 mutation 是更改状态的唯一方法,并且这个过程是同步的。
-
异步逻辑都应该封装到 action 里面。
只要你遵守以上规则,如何组织代码随你便。如果你的 store 文件太大,只需将 action、mutation、和 getters 分割到单独的文件。
即因为应用比较复杂,所以store的创建导出、action、mutation等代码都比较复杂时,为了使逻辑更为清晰,我们不是将vuex写在一个js文件中,而是分开写,并且放在store文件夹下。
结束