不能直接将 websocket 实例存入 vuex state,因为其非响应式、刷新后丢失、易被覆盖且高频 commit 会拖慢渲染;应分离连接层(如 usewebsocket)与业务状态层(vuex/pinia),仅存业务数据。

直接把 new WebSocket() 放进 Vuex 的 state 里,连接实例会在页面刷新后丢失,且无法被 Vue 响应式系统追踪——这不是“保存”,只是挂了个引用,实际不可靠。
为什么不能直接把 websock 存进 Vuex state
Vuex 的 state 是响应式数据容器,但原生 WebSocket 实例本身不可响应,也不支持深度监听。更关键的是:
– 页面刷新后 state 重置,websock 变成 null,连接彻底断开;
– 多个组件 commit 同一个 mutation 修改 state.websock,容易覆盖或误关;
– onmessage 回调里直接 commit,若消息量大、频率高,会频繁触发 Vuex 状态同步,拖慢渲染。
useWebSocket + ref 才是 Vue3 的正确姿势
用 @vueuse/core 的 useWebSocket 替代手写连接逻辑,它返回的 ws 是一个 Ref,天然适配组合式 API,且内置重连与心跳(无需手动 setInterval):
import { useWebSocket } from '@vueuse/core'
const { data, status, send, close } = useWebSocket('wss://echo.websocket.events', {
autoReconnect: { retries: 3, delay: 1000 },
onConnected: () => console.log('✅ 已连接'),
onDisconnected: () => console.log('⚠️ 已断开'),
onError: (e) => console.error('❌ 连接异常', e),
})
要点:
– data 是 Ref<string null></string>,服务端发来的消息自动更新,组件内可直接 {{ data }} 或 watch(data, ...);
– 不要把 data 或 send 塞进 Vuex,它们本就是跨组件可访问的响应式引用;
– 若需全局发送,导出一个带 send 的工具函数即可,避免污染 store。
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
Vuex(或 Pinia)只管“业务消息”,不管“连接实例”
真正该进 Vuex/Pinia 的,是解析后的业务数据,比如告警列表、未读数、在线用户状态等:
// store/modules/websocket.js
const state = () => ({
alerts: [],
unreadCount: 0,
onlineUsers: []
})
const mutations = {
ADD_ALERT(state, payload) {
state.alerts.push(payload)
state.unreadCount++
},
CLEAR_ALERTS(state) {
state.alerts = []
state.unreadCount = 0
}
}
const actions = {
// 在 setup 中调用 useWebSocket 后,把消息 dispatch 到这里
receiveAlert({ commit }, alertData) {
commit('ADD_ALERT', alertData)
}
}
这样做的好处:
– 连接层(useWebSocket)和业务层(Vuex)职责分离,改重连策略不影响状态逻辑;
– 消息进 store 前可统一做格式校验、去重、节流;
– 导航栏小红点、弹窗、列表页,都从同一个 unreadCount 拿数据,不会不一致。
Vue2 项目必须用 Vuex?那得绕开 state 存实例的坑
Vue2 中若坚持用 Vuex,切记:
– state.websock 只作标记位(如 status: 'connecting' | 'open' | 'closed'),不要存实例;
– 实际 WebSocket 实例应放在单例类或 Vue.prototype 上(如 Vue.prototype.$ws);
– 所有 onmessage 处理逻辑收口到一个中央方法,再由它调用 this.$store.dispatch(...);
– 心跳包发送不要写在 mutation 里,而应在连接建立后单独启动定时器,并确保页面隐藏时暂停(用 document.visibilityState 判断)。
最易被忽略的一点:无论用哪种封装,服务端返回的每条消息都应带唯一 id 或时间戳,前端做幂等处理——网络抖动导致重复投递、重连后消息补发,都可能让同一条告警触发两次 ADD_ALERT。这个逻辑不在连接层,而在进 store 前的校验环节。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










