Plug the (Web)socket

Antoine Jaussoin
Around the App in 365 days
4 min readApr 6, 2018

My reality needs imagination like a bulb needs a socket. My imagination needs reality like a blind man needs a cane.
Tom Waits

This week, we are going to add some basic websocket communication between our clients.

What are Websockets you may ask? It is a protocol allowing for two-ways, always “on” communication channel between a client and a server.

HTTP, which is the underlying protocol for REST requests (see previous article), is stateless, fire-and-forget. You make a request, the server responds, that’s it.

Sometimes though, we want to keep the “line open” between our server and our client, to enable real-time communication: enter Websockets.

What we are going to do today is add some very simple client-side interaction, by allowing the user to select cards. And we will synchronise, in real-time, this selection across all clients.

This is of course only a basic example, where everyone “sees” the same thing, but it’s a step towards our implementation of the planning poker game.

Is it like peer-to-peer? Not really: the communication is always between the client and the server, never client-to-client directly. To enable client-to-client communication, you actually send your message to the server, who will then send it back to the other client(s).

Adding some client-side interaction (commit)

In this commit, we are going to slightly modify our app to add a new feature: the ability to select cards from the deck (which we get from the server, see previous article), and add these to a selection.

First, we need to make a few adjustments to our Card component: if you look at the Card/index.js file in our commit, you will see that we added two things:

  • An onClick handler, allowing the Card to respond to clicks
  • A CSS change, making the mouse cursor look like a hand pointer, to tell the user that the card is clickable.

Second, we need to make some layout adjustments, by creating a few new divs (lines 16, 21 and 25) in the App.js. They will be the containers for our page, our deck and our selection respectively.

On Line 31, you can see that we added a new array to our state: selection . This is the array we are going to add cards in, each time we click on a card in the deck.

Then on line 39, we add a method to handle adding the card to the selection: we set a new selection array on the state, using the previous array and adding the card as the last item.

Why didn’t we mutate the existing array by doing selection.push(card) ? Because React wants the state and the props to be immutable, so when we do [ ...oldArray, newItem ] we actually create a new array.

Last but not least, we put all this together in the render method, displaying the cards for both the deck and our selection.

Voilà!

Introducing Socket.io (commit)

First, lets install some new dependencies:

yarn add socket.io socket.io-client

Since we are adding some client-server communication, we need to modify both.

The Server

Configuring the server is pretty easy: you connect Socket.io to your existing Express app, on line 7.

Then you use io.on('connection', ...) to handle every client connecting to your server through websockets. Each new client will display a message on your server console, and receive the current selection by doing a socket.emit() (line 34).

You also need to handle any updates to that selection, by listening on the SEND_SELECTION message, on line 37. Each time this message is sent by one of the client, the server will respond by broadcasting this selection to everyone else (line 40).

Before we go see what happens on the client side, you also need to modify your package.json file to add a new proxy rule for the socket.io endpoint (line 31). Without that, the client won’t find the socket.io endpoint when you work on your local machine.

The Client

On the client, the process is similar: we instanciate a new Websocket connection by calling the io() function on line 40.

We listen to the RECEIVE_SELECTION messages, and update our local selection everytime the server sends a new one (line 49).

If it is our client doing the change in the selection (by clicking on one of the cards), we need to notify the server: on the selectCard method, we wait until the new state is set (so we hook to the setState function callback) to send a message to the server about sending a new selection (using aSEND_SELECTION message, with the new selection as a payload).

The Result

Once you’ve checked out the code, run the server and open two (or more) browsers:

You will see that whenever you add a card to the selection, all the browsers update the selection at the same time: they are kept in sync!

If you kill the server, you will also notice that all selections are cleared, and any new selection is not synchronised.

--

--