为什么要写这篇文章呢?因为很多新手对vuex都懵懵懂懂,不是很了解vuex到底是怎么用的;一方面是想从最简单最基础的地方带大家使用一下vuex,另一方面也是想让自己复习一下vuex。好,废话就不多讲了,来跟我一起来学习vuex吧。
vuex有五大核心概念,搞清楚就够了。
一、原生状态state
二、修饰器getters
三、修改值mutations
四、异步操作actions
五、模块化管理modules
在学习使用之前,我们首先要了解vuex是什么?那vuex是什么呢?在学习一样新东西之前,我们首先要考虑的就是进它的官网,没错,那里的答案可能不是最好理解的,但一定是最完整的。
image.png
如图,简单来说,它就是一个状态管理器。在日常的开发中,我们往往会遇到以下两个问题:
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
这就是 Vuex 背后的基本思想,借鉴了 Flux \(opens new window\)[1]、Redux \(opens new window\)[2]和 The Elm Architecture \(opens new window\)[3]。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
image.png
Vuex 可以帮助我们管理共享状态,并附带了更多的概念和框架。这需要对短期和长期效益进行权衡。如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。使用父子通信或者$bus就可以解决。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。
在构建架手架时,你可以选择直接一起安装,这个时候,vux会自动给你下载依赖包并建好相关文件。但如果你没有选择,就需要自己下载依赖,在src下新建store文件夹,这个文件夹与路由router同级,并在main.js引入注册使用。
image.png
image.png
每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state) 。Vuex 和单纯的全局对象有以下两点不同:
1.1、在仓库里面定义原生状态
image.png
1.2、在页面直接访问(不推荐)
image.png
这种方法是不建议的,但是不代表不能使用,vuex推荐我们在computed中使用。
1.3、使用方法访问
image.png
image.png
1.4、使用mapState
辅助函数访问
官方解答:当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用 mapState
辅助函数帮助我们生成计算属性,让你少按几次键:
image.png image.png
上面的代码展示了,你可以用mapState辅助函数简化写法,你还可以对它取别名,使用外号。(取别名是对象,不是数组)
有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行颠倒:你想到的是不是在取到state的值了之后,就行数据处理,这样不能说的错的,但是你想想,如果多个组件都要使用这个颠倒的数据,那你是不是得在每个组件获取到值后再处理一遍,这是十分不理想的。Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。Getter 接受 state 作为其第一个参数
2.1、在仓库里定义getters方法
image.png
2.2、使用方法访问
image.png
2.3、使用mapGetters辅助函数访问
是不是觉得直接使用方法访问有点傻,getters也有status类似的辅助函数,也支持取小名哦。(取别名是对象,不是数组)
image.png
说到修改值,有的同学就会想到这样写: // 错误示范 this.$store.state.XXX = XXX;
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler) 。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
3.1在仓库中定义Mutation
3.2 在组件中提交 Mutation(Mutation 通过 store.commit
方法触发)
你不能直接调用一个 mutation handler。这个选项更像是事件注册:“当触发一个类型为 add
的 mutation 时,调用此函数。”要唤醒一个 mutation handler,你需要以相应的 type 调用 store.commit 方法。
3.3使用辅助函数mapMutations提交(支持改小名)
image.png
3.4使用对象风格的提交方式(官方推荐)
mutations: {
increment (state, payload) {
state.count += payload.amount
}
}
复制代码
Mutation需遵守 Vue 的响应规则
既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
使用 Vue.set(obj, 'newProp', 123)
, 或者
以新对象替换老对象。例如,利用对象展开运算符 \(opens new window\)[4]我们可以这样写:
state.obj = { ...state.obj, newProp: 123 }
复制代码
一条重要的原则就是要记住 mutation 必须是同步函数
在 mutation 中混合异步调用会导致你的程序很难调试。例如,当你调用了两个包含异步回调的 mutation 来改变状态,你怎么知道什么时候回调和哪个先回调呢?这就是为什么我们要区分这两个概念。在 Vuex 中,mutation 都是同步事务:Action 类似于 mutation,不同在于:
4.1、让我们来注册一个简单的 action:
image.png
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit
提交一个 mutation,或者通过 context.state
和 context.getters
来获取 state 和 getters。当我们在之后介绍到 Modules[5] 时,你就知道 context 对象为什么不是 store 实例本身了。
实践中,我们会经常用到 ES2015 的 参数解构 \(opens new window\)[6]来简化代码(特别是我们需要调用 commit
很多次的时候)
4.2、在组件中分发 Action (Action 通过 store.dispatch
方法触发)
image.png
4.3使用mapActions辅助函数分发Action(支持改小名)
image.png
4.4使用对象风格的提交方式(官方推荐)
actions: {
incrementAsync ({ commit }) {
setTimeout(() => {
commit('increment')
}, 1000)
}
}
复制代码
于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module) 。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割
然后在index里面对模块进行引入注册:
image.png image.png
对应上面的四大核心概念使用方法就得加入模块的使用方法。
image.png
image.png
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8