JavaScript: how to handle WebSocket streams with SPA frameworks

JavaScript: how to handle WebSocket streams with SPA frameworks

In this article we'll take a deep look at how to handle WebSocket streams with SPA JavaScript frameworks.

In this article we'll take a deep look at how to handle WebSocket streams with SPA JavaScript frameworks.

When we use plain JavaScript, we can usually create and insert new elements while the incoming streaming is being received within the message event.

const ws = new WebSocket('ws://api.tld:8000/ws/ping-command/');
const response = document.getElementById('response');
const form = document.getElementById('ping-form');

ws.onmessage = evt => {
      const line = document.createElement('li');
      line.textContent = evt.data;
      response.appendChild(line);    
};

form.addEventListener('submit', e => {
    e.preventDefault();
    ws.send(form.querySelector('#host').value);
}, false);

Depending on the number of ping requests sent by the server, the expected output will result in a progressive sequence of new lines appended one at time.

With frameworks like React and Vue.js, instead, we have to consider the final output as a single buffer array that needs to be progressively filled untilt there's no more data in the incoming output stream.

For example, in Vue.js we can take the following approach.

<script setup>
import {ref, reactive} from 'vue';

const response = reactive({
  content: [],
});
const host = ref('');

const ws = new WebSocket('ws://api.tld:8000/ws/ping-command/');

ws.onmessage = event => {
  response.content.push(event.data);
};

const handleSubmit = () => {

  response.content = [];
  ws.send(host.value.trim());
};
</script>

<template>
    <form @submit.prevent="handleSubmit">
            <div>
                    <input type="text" v-model="host">
                    <button type="submit">Ping</button>
            </div>
    </form>
    <pre v-if="response.content.length > 0">
        <div v-for="line in response.content" :key="line">{{ line }}</div>
    </pre>
</template>

In other words, we need a data structure in this particular case that we can use as a temporary storage for the incoming data. We want to preserve the visual effect of data that flows into the page line by line. Since here we're dealing with text lines, the data structure is going to be a list which takes the form of an array in the JavaScript language.