0x00 写在前面
最近的项目中用到了websocket实现实时通信。遇到了一个问题:如何将websocket服务器端实时推送过来的数据全局实时推送。由于websocket通信的实时性和vue中的渲染机制。在查了很多资料之后,发现vuex是实现这个功能的最佳选择。
上图中展示了一个状态自管理应用中的单向数据流。由 state,驱动应用的数据源;view,以声明方式将 state 映射到视图;actions,响应在 view 上的用户输入导致的状态变化 三部分组成。当遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
这时,将组件的共享状态抽取出来,以一个全局单例模式管理。在这种模式下,组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!这就是vuex的设计思想。
0x01 什么是vuex?
vue官方说法中,Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
如上图所示,Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex 和单纯的全局对象有以下两点不同:
Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。
不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样可以方便跟踪每一个状态的变化。
0x02 关于State
Vuex 使用单一状态树:用一个对象包含全部的应用层级状态。由于 Vuex 的状态存储是响应式的,从 store 实例中读取状态最简单的方法就是在计算属性中返回某个状态:
|
|
每当 store.state.count 变化的时候,都会重新求取计算属性,并且触发更新相关联的 DOM。这种模式导致组件依赖全局状态单例。在模块化的构建系统中,在每个需要使用 state 的组件中需要频繁地导入,并且在测试组件时需要模拟状态。
Vuex 通过 store 选项,提供了一种机制将状态从根组件“注入”到每一个子组件中(需调用 Vue.use(Vuex))。通过在根实例中注册 store 选项,该 store 实例会注入到根组件下的所有子组件中,且子组件能通过 this.$store 访问到。
当一个组件需要获取多个状态时候,将这些状态都声明为计算属性会有些重复和冗余。这时可以使用 mapState 辅助函数帮助我们生成计算属性。
|
|
0x03 关于Mutations
提交 mutation是更改Vuex 的 store 中的状态的唯一方法。mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数:
mutation handler不能直接被调用,Mutations以相应的type通过调用store.commit(‘increment’)触发 mutation handler
|
|
0x04 关于Actions
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作。123456789101112131415const store = new Vuex.Store({state: {count: 0},mutations: {increment (state) {state.count++}},actions: {increment (context) {context.commit('increment')}}})
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此可以通过调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters。实践中,经常会用到 ES2015 的 参数解构 来简化代码(特别是需要多次调用 commit 的时候):
Action 通过 store.dispatch 方法触发:
|
|
这个方式就体现了action与mutation 的不同之处:mutation 必须同步执行,而Action 就不受约束!可以在 action 内部执行异步操作:
0x05 项目中的思路
项目结构如下所示:其中Web.vue是整个页面的根组件,于是我将websocket的实时通信写在了这里。
在建立连接之后,当有用户上线,后端就向前端实时推送数据,并使用this.$store.dispatch将后端推送的数据保存为store里的一个state。
5.1 实时通信
|
|
5.2 使用Vuex管理新用户上线
然后,在src文件夹下新建一个/store/index.js文件,引入vuex来进行全局状态管理。在state里面定义一个全局变量data。在mutations里面定义一个dataPush函数,更改state状态。当接收到新用户上线的数据推送时,就会触发store里面的dataPush函数,修改store里面的数据状态。
5.3 监听状态更新,进行提示
最后,在web.vue页面建立一个监听事件,监听$store.state.data这个状态是否有更新,如果有更新,就使用一个提示组件,展示新上线的用户信息。
|
|