A Socket.io tutorial that ISN'T a chat app (with React.js)
Tags: tutorial, socketio, websockets, javascript
Published: 2019-04-07 02:40:07

---
title: A Socket.io tutorial that ISN'T a chat app (with React.js)
published: true
description: A socket io tutorial
tags: tutorial,socket.io,websockets,JavaScript
---

# A Socket.io tutorial that _ISN'T_ a chat app (with React.js)

Recently, a friend asked for advice for displaying sensor data in real-time (or as near-real-time as possible) on to a dashboard. Specifically, he'd be reading OBD2 data from a drag racing car and wanted to display some data points to an external system. After considering a message bus like Kafka, we decided it was way over kill. I recommended using websockets, specifically, the Socket.io implementation of them. To be fair, I'd never used the Socket.io library, I'd only read about them and I had a surprisingly difficult time finding information on how to use them outside of a chat app or a multiplayer game. To me, translating the chat-room app tutorial found on [Socket.io](https://socket.io/get-started/chat/) into a different use case was a bit of a process, so I decided to write up this little demo which may be useful to someone in thinking about sockets a different way.

## The 3 layers

Here's the super high level design we came up with:
![I Like Memes](https://thepracticaldev.s3.amazonaws.com/i/mw9b6z27mfttcelju3cv.png)

For our prototype, well be simulating the sensor/reader, setting up a backend server as a pass-through, and implementing a front end consumer.

## The Backend
The two packages we'll need are:

* [express](https://www.npmjs.com/package/express) 
* [socket.io](https://www.npmjs.com/package/socket.io) 

```javascript
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");

//Port from environment variable or default - 4001
const port = process.env.PORT || 4001;

//Setting up express and adding socketIo middleware
const app = express();
const server = http.createServer(app);
const io = socketIo(server);

//Setting up a socket with the namespace "connection" for new sockets
io.on("connection", socket => {
    console.log("New client connected");

    //Here we listen on a new namespace called "incoming data"
    socket.on("incoming data", (data)=>{
        //Here we broadcast it out to all other sockets EXCLUDING the socket which sent us the data
       socket.broadcast.emit("outgoing data", {num: data});
    });

    //A special namespace "disconnect" for when a client disconnects
    socket.on("disconnect", () => console.log("Client disconnected"));
});

server.listen(port, () => console.log(`Listening on port ${port}`));
```

Lets break this down:
```javascript
const express = require("express");
const http = require("http");
const socketIo = require("socket.io");

//Port from environment variable or default - 4001
const port = process.env.PORT || 4001;

//Setting up express and adding socketIo middleware
const app = express();
const server = http.createServer(app);
const io = socketIo(server);
```

If you've used express before, most of this isn't anything new. The only socket.io related stuff we see here is `const io = socketIo(server);` which sets up a new server instance of socket.io.

```javascript
//Setting up a socket with the namespace "connection" for new sockets
io.on("connection", socket => {
    console.log("New client connected");

    //Here we listen on a new namespace called "incoming data"
    socket.on("incoming data", (data)=>{
        //Here we broadcast it out to all other sockets EXCLUDING the socket which sent us the data
       socket.broadcast.emit("outgoing data", {num: data});
    });

    //A special namespace "disconnect" for when a client disconnects
    socket.on("disconnect", () => console.log("Client disconnected"));
});

server.listen(port, () => console.log(`Listening on port ${port}`));
```

Here we're setting up a socket namespace called `connection` which is where clients will connect to. Once an initial connection is made, we listen on two new namespaces. `incoming data` and `disconnect`. The first one is where our "producer" or sensor/reader will be pushing data too. 

In our callback we call `socket.broadcast.emit("outgoing data", {num: data});`. The broadcast flag is special because it allows us to emit data to every client EXCEPT the one that sent us the data. There's no point in sending data back to the producer so we broadcast on yet another namespace, `outgoing data`.

You'll notice we serialize our incoming data before pushing to our `outgoing data` namespace. This will make it cleaner on our front end and will give you an idea about how we can send multiple data points in one emit. 

The disconnect namespace is reserved for when a client loses connection. It is a good place to do any cleanup. For example, if your server is keeping track of clients that are connected, its a good spot to change the state of the client to disconnected.

The final line is setting up our express app to start listening.

## The simulated sensor

Since this is a simulation, all we need to do is send some random data. For the prototype, this was done in pure node.js but there are many client libraries available for socket.io that would most certainly be better for running on an Arduino or other micro-controllers that would attach to a OBD2 sensor. Don't roast me too hard here, it's just a demo.

For this demo, I'll be demoing a "speed" value.

The only package we used here is [socket.io-client](https://www.npmjs.com/package/socket.io-client). 

```javascript
let socket = require('socket.io-client')('http://127.0.0.1:4001');

//starting speed at 0
let speed = 0;

//Simulating reading data every 100 milliseconds
setInterval(function () {
    //some sudo-randomness to change the values but not to drastically
    let nextMin = (speed-2)>0 ? speed-2 : 2;
    let nextMax = speed+5 < 140 ? speed+5 : Math.random() * (130 - 5 + 1) + 5;
    speed = Math.floor(Math.random() * (nextMax - nextMin + 1) + nextMin);

    //we emit the data. No need to JSON serialization!
    socket.emit('incoming data', speed);
}, 100);

```

Most of this should be pretty self-explanatory, so this section will be short.
`let socket = require('socket.io-client')('http://127.0.0.1:4001');` sets up the package to be used. We start out setting out speed variable to 0.

`let socket = require('socket.io-client')('http://127.0.0.1:4001');` returns to us the socket connection to be used. We're telling it where its running and what port its running on. 

I used `setInterval` here to simulate read requests between a micro-controller and a sensor every 100 milliseconds. The math to set the next speed is just a "hack-y" way to increase or decrease the speed slightly every time and not to allow the speed to be over 140 or below 0. 

`socket.emit('incoming data', speed);` is where we emit the data through the socket. We emit the data on the `incoming data` namespace which we've set up on the backend in the previous section. 

That's it! Cool huh?

## The Dashboard

I built this in React and it was super easy and quick. I'm not going to get into the React details as its out of scope. I'm going to focus on how to consume the data from a socket. That being said, I used [react-d3-speedometer](https://www.npmjs.com/package/react-d3-speedometer) to display a speedometer. I've gotta say I'm really impressed with the way it look! I'm also using the same [socket.io-client](https://www.npmjs.com/package/socket.io-client) package that we used on the producer.

Here's the React component:

```react
import React, {Component} from "react";
import socketIOClient from "socket.io-client";
import ReactSpeedometer from "react-d3-speedometer"

class App extends Component {
    constructor() {
        super();
        this.state = {
            response: 0,
            endpoint: "http://127.0.0.1:4001"
        };
    }

    componentDidMount() {
        const {endpoint} = this.state;
        //Very simply connect to the socket
        const socket = socketIOClient(endpoint);
        //Listen for data on the "outgoing data" namespace and supply a callback for what to do when we get one. In this case, we set a state variable
        socket.on("outgoing data", data => this.setState({response: data.num}));
    }

    render() {
        const {response} = this.state;
        return (
            <div style={{textAlign: "center"}}>
                <ReactSpeedometer
                    maxValue={140}
                    value={response}
                    needleColor="black"
                    startColor="orange"
                    segments={10}
                    endColor="red"
                    needleTransition={"easeElastic"}
                    ringWidth={30}
                    textColor={"red"}
                />
            </div>
        )
    }
}

export default App;
```

`state.response` will hold the value coming from the backend and `state.endpoint` is just where the server is located. The magic happens in the lifecycle function `componentDidMount()`. For those of you unfamiliar with React, this function is called when the component is added to the DOM. Hence, this is where well connect to the socket and listen for data.

`const socket = socketIOClient(endpoint);` simply connects us to the server and opens up a socket connection. 

`socket.on("outgoing data", data => this.setState({response: data.num}));` looks familiar doesn't it? We begin listing on the `outgoing data` namespace. We have a callback which then takes the response and sets the state to the new value. 

Lets take a look at the render function:
```react
    render() {
        const {response} = this.state;
        return (
            <div style={{textAlign: "center"}}>
                <ReactSpeedometer
                    maxValue={140}
                    value={response}
                    needleColor="black"
                    startColor="orange"
                    segments={10}
                    endColor="red"
                    needleTransition={"easeElastic"}
                    ringWidth={30}
                    textColor={"red"}
                />
            </div>
        )
    }
```

The ReactSpeedometer component has a bunch of props you can pass to it to customize it. Most of it is self-explanatory but you can read all about it [here](https://www.npmjs.com/package/react-d3-speedometer#configuration-options). I used the needleTransition "easeElastic" because it looks cool but "eastLinear" is probably a better choice for a speedometer. Read about the transition effects [here](https://github.com/d3/d3-ease#api-reference).

The render function extracts the current state value for the speed and pass it into the ReactSpeedometer prop named `value`. This will update the speedometer.

## So how does it look!

[https://i.imgur.com/D4qzm7o.gif](https://i.imgur.com/D4qzm7o.gif)
(Having issues embedding the gif in this post. Sorry!)

It ended up behaving more like a tachometer but turned out pretty cool!