0 day streak
javascript / intermediate
Snippet

Bridging Class-Based State Machines with Vue Reactivity for Real-Time Sockets

Encapsulating networking lifecycles and private WebSocket instances inside an ES6 class keeps connection logic decoupled from UI concerns. By passing a callback that updates a Vue `ref`, the class instance safely drives the reactive state while `onScopeDispose` guarantees teardown when the calling component unmounts.

snippet.js
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import { ref, onScopeDispose } from 'vue';
class SocketSessionController {
#socket = null;
#onStateChange;
constructor(url, onStateChange) {
this.url = url;
this.#onStateChange = onStateChange;
}
connect() {
this.#socket = new WebSocket(this.url);
this.#socket.onopen = () => this.#onStateChange('CONNECTED');
this.#socket.onclose = () => this.#onStateChange('DISCONNECTED');
this.#socket.onerror = () => this.#onStateChange('ERROR');
}
disconnect() {
if (this.#socket) {
this.#socket.close();
this.#socket = null;
}
}
}
export function useRealtimeConnection(endpoint) {
const connectionState = ref('DISCONNECTED');
const controller = new SocketSessionController(endpoint, (newState) => {
connectionState.value = newState;
});
controller.connect();
onScopeDispose(() => controller.disconnect());
return { connectionState };
}
vue
Breakdown
1
class SocketSessionController { #socket = null;
Defines an ES6 class with a private field to securely hold the underlying WebSocket instance.
2
this.#socket.onopen = () => this.#onStateChange('CONNECTED');
Invokes the state-change callback to broadcast connection transitions to listeners.
3
const controller = new SocketSessionController(endpoint, (newState) => {
Instantiates the controller class within a Vue composable, connecting class events to a reactive ref.
4
onScopeDispose(() => controller.disconnect());
Hooks into Vue's effect scope disposal to clean up socket resources and prevent memory leaks.