一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情。
代码最小粒度不在Vue组件,在JS文件
可能有人会奇怪,代码不都写在Vue组件里面,为什么还要在JS文件使用Vuex数据状态?
不是的,因为随着项目的规模越来越大,职责划分变得尤为重要,不能把所有代码都写在Vue组件中。代码最小划分粒度,可能会是一个个独立的JS文件,通过标准的ESModule来彼此衔接和应用。
业务背景
Vuex Store的auth模块下,有个authorized
状态,用来标识WebSocket连接是否建立且授权通过。
之所以这个标识维护在Vuex,是因为页面需要通过一个图标显示通信是否正常,且允许手动点击来关闭WebSocket连接。
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import auth from './modules/auth'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
auth,
},
})
export default store
store/modules/auth.js
export default {
namespaced: true,
state: {
authorized: false, // 标识
},
mutations: {
SET_AUTH(state, authorized) {
state.authorized = authorized
},
},
}
同时,有一个neffos.js
文件负责进行WebSocket连接,需要引用authorized状态,每当send()
方法被调用发送数据时,先要判断authorized为true才发送,否则收集进入消息队列。
还要监听authorized
重新为true时,遍历消息队列,依次推送消息。
websocket/neffos.js
import store from '@store'
const queue = []
// 监听authorized为true时,发送消息队列
// if (authorized) {
// while (queue.length > 0) {
// const msg = queue[0]
// this.nsConn.emit('message', msg)
// queue.shift()
// console.log('queue emit', msg)
// }
// }
/*
* 发送信息
*/
send(commandKey, data) {
const msg = JSON.stringify(commandKey, data)
// 将标识放在方法体内,每次调用都获取最新的
const { authorized } = store.state.auth
if (authorized && this.nsConn) {
this.nsConn.emit('message', msg)
console.info('neffos send', msg)
} else {
queue.push(msg)
}
}
问题描述
如果上述代码在Vue组件中,一切都好办,我们可以把authorized
挂载到computed
中,还可以通过watch
来监听数据的变化。
但是WebSocket只负责通信事宜,和视图无关的,理应封装在独立js文件,这样后期还可以迁移到jQuery或者React项目。
而问题就在于,将store.state
赋值给独立js文件中的变量,是不具备响应式的,且无法监听它是否发生了变化。
思路1:借助EvenBus进行通知(不推荐)
store/modules/auth.js
// 引入事件总栈
import EventBus from '@event-bus'
export default {
namespaced: true,
state: {
authorized: false,
},
mutations: {
SET_AUTH(state, authorized) {
state.authorized = authorized
// 当赋值为true时,发送通知
if(authorized){
EventBus.emit('authSuccess')
}
},
},
}
websocket/neffos.js
import store from '@store'
import EventBus from '@event-bus'
const queue = []
// 监听authorized为true时,发送消息队列
EventBus.on('authSuccess', () => {
while (queue.length > 0) {
const msg = queue[0]
this.nsConn.emit('message', msg)
queue.shift()
console.log('queue emit', msg)
}
})
思路2:Store.watch监听(推荐)
其实Vuex Store实例本身就提供了watch
方法,用于监听state或者getters数据的变化。这样就不用增加EventBus的订阅,少写代码减少程序的复杂度,也让逻辑更清晰。
websocket/neffos.js
import store from '@store'
import EventBus from '@event-bus'
const queue = []
// 监听authorized为true时,发送消息队列
store.watch(
// 第一个参数是箭头函数,用来选择你要监听的数据
(state,getters) => state.auth.authorized,
// 第二参数也是箭头函数,是数据改变后的回调监听
authorized => {
if (authorized) {
while (queue.length > 0) {
// 发一个删一个,确保发送顺序
const msg = queue[0]
this.nsConn.emit('message', msg)
queue.shift()
console.log('queue emit', msg)
}
}
},
)