Going real time with Socket.IO, Node.Js and React

Looks like everybody is building chat apps with Socket.IO these days and while that’s completely fine, messaging applications are only the tip of the iceberg. Think a moment about it: there are literally a million of other things you can build within the real-time domain.

In the following post I would like to explore some interesting use cases and hopefully give you ideas about what to build next with Socket.IO. We will start with some basic concepts all the way through exploring what Socket.IO and React can do for us when paired together.

By the end of the article you will build a super simple real-time application:

Socket.IO and React paired together

That will be quite a long post! Grab a cup of tea and take a seat before getting started!

What you will learn

  1.  What a WebSocket is
  2. How to Use Socket.IO and Node.js alongside with React

Requirements

In order to follow along with this tutorial you should have a basic understanding of Javascript, Node.js, and ExpressJS.

The latest version of Node.js is available from the Node.js

If you use Linux, you should absolutely check out Nodesource: they offer Node.js 8.x.x and NPM 5.x.x

Last but not least, if you haven’t got an API key from DarkSky yet, go grab one: we will use the DarkSky API later on inside our ExpressJS application.

The WebSocket protocol, Node.js and Socket.IO

WebSocket is basically an internet communication protocol with a relevant interesting feature: it provides a full-duplex channel over a single TCP connection.

With WebSockets, a client and a server will be able to talk to each other in real time, kind of like they were involved in a telephone call: once connected, a client will be able to receive data from the server, without any need to continuously refresh the web page. On the other hand the server will also be able to receive data in real time from the client inside the same connection.

What’s more interesting is the WebSockets ability to work with an event-driven model: both the server and the client can react to events and messages.

WebSockets opened up an entire world of opportunities for web developers. If you’re wondering how to implement this fantastic tecnology into your Node.js applications, well, the answer is Socket.IO, one of the most popular real-time engines for Node.js.

Socket.IO logo
Socket.IO is one of the most popular real-time engines for Node.js

Socket.IO works mostly by the means of Node.js events: you can listen for a connection event, fire up a function when a new user connects to the server, emit a message (basically an event) over a socket, and much more.

Socket.IO is used by countless companies and developers. It found its way through instant messaging applications, real-time analytics and monitoring, and it is used also for streaming and document collaboration.

However one thing to keep in mind is that Socket.IO is not an WebSocket implementation.

The authors state that “Socket.IO indeed uses WebSocket as a transport when possible [..] but a WebSocket client will not be able to connect to a Socket.IO server, and a Socket.IO client will not be able to connect to a WebSocket server”.

Besides that, the framework behaves exactly like WebSockets and here lies its power: with this in place and with a basic understanding of the Websocket procotol, it’s time to get our hands dirty.

Building a real-time server: scaffolding the project

To start with, create an empty directory named socket-io-server:

mkdir socket-io-server

then move inside the newly created directory:

cd socket-io-server

and initialize the package.json by running:

npm init

We won’t publish any module to NPM so you can safely accept the default choices and just move on.

We also need to install Socket.io, which is the main dependency of our project, ExpressJS, and Axios. Express will help us building the server and Axios will be used to make HTTP requests to the DarkSky API :

npm i axios express socket.io

Building a real-time server: the code

So, the idea behind our little project is simple: Caty wants to know the current temperature in Florence and maybe also have the possibility to get an update every 10 seconds.

You might be tempted to put a call to DarkSky inside the componentDidMount of a React component. Maybe you should poll the API every 10 seconds with a call to setInterval directly inside componentDidMount?

Yes I’m guilty, I’ve done things like that in the recent past, and you must remember to clean the interval every time the component gets unmounted. Luckily, there are better ways: in our case, a simple real-time server will get the job done.

The server will use Socket.IO to emit a message every 10 seconds and the client will listen for the same message over a real-time socket. Sounds neat? It is.

Am I going to put React into the mix when I could have simply rendered the HTML with Pug or Jade? Yes, because it is very interesting to see how React can work alongside with Socket.IO.

You’ll see soon.

Create a file named app.js inside your project’s directory. This will hold the actual server:

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

const port = process.env.PORT || 4001;
const index = require("./routes/index");

const app = express();
app.use(index);

const server = http.createServer(app);

const io = socketIo(server); // < Interesting!

const getApiAndEmit = "TODO"

The code above should be no mistery for you: it is a bunch of requires followed by the instantion of a new ExpressJS application. What’s rather interesting there is the call to socketIo() to initialize a new instance by passing in the server object. By doing so we have wired up the ExpressJS server to Socket.IO.

You should also have noticed a empty function:

const getApiAndEmit = "TODO"

we will fill it with some meaningful code next up.

Notice also how the application calls the index route: even if the server won’t serve any HTML content we will need a very simple route in order to listen for any incoming connection.

Create a file named index.js inside the routes directory:

const express = require("express");
const router = express.Router();

router.get("/", (req, res) => {
  res.send({ response: "I am alive" }).status(200);
});

module.exports = router;

and you’re done.

How does Socket.IO works by the way?

The first and most important method you will encounter while working with Socket.IO is on(). The on() method takes two arguments: the name of the event, in this case “connection” and a callback which will be executed after every connection event. on() is nothing more than a core Node.js method tied to the EventEmitter class.

The connection event returns a socket object which will be passed to the callback function. By using said socket you will be able to send data back to the client in real time.

If you remember, Caty wants to know the temperature every 10 seconds: we can use setInterval inside the callback, and inside setInterval we can use another arrow function which will call the getApiAndEmit function we saw earlier. The code should be really straightforward:

io.on("connection", socket => {
  console.log("New client connected"), setInterval(
    () => getApiAndEmit(socket),
    10000
  );
  socket.on("disconnect", () => console.log("Client disconnected"));
});

Notice also how we can listen for the disconnect event. It will be fired as soon as a client disconnects itself from the server. For now we will just print a simple message to the console.

IMPORTANT: As pointed out by some fellow readers, the code above has a flaw: it creates a new interval for every connected client. While Socket.IO was born to handle many concurrent connections our example assumes that only one user will visit the page: you. If you were to put that code in production, just don’t. A more serious version of the above snippet would clear the interval upon subsequent connections:

let interval;

io.on("connection", socket => {
  console.log("New client connected");
  if (interval) {
    clearInterval(interval);
  }
  interval = setInterval(() => getApiAndEmit(socket), 10000);
  socket.on("disconnect", () => {
    console.log("Client disconnected");
  });
});

Anyway, for the scope of this post it’s completely fine to go without clearing the interval id at all.

Now we can make the application listen for incoming connections:

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

Do you remember our getApiAndEmit function? It takes the socket as an argument. The socket is nothing more than the communication channel between the client and the server. We can write whatever we want inside it by emitting a message:

const getApiAndEmit = async socket => {
  try {
    const res = await axios.get(
      "https://api.darksky.net/forecast/PUT_YOUR_API_KEY_HERE/43.7695,11.2558"
    ); // Getting the data from DarkSky
    socket.emit("FromAPI", res.data.currently.temperature); // Emitting a new message. It will be consumed by the client
  } catch (error) {
    console.error(`Error: ${error.code}`);
  }
};

The function takes the socket as an argument, makes an HTTP request to the DarkSky API (don’t forget to fill the url with your actual API key), and finally emits the message “FromAPI” which will contain the current temperature value for the given coordinates.

The emitted message can be intercepted by the Socket.IO client (React in our case).

Server wise we are done and the complete code for app.js should look like this:

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

const port = process.env.PORT || 4001;
const index = require("./routes/index");

const app = express();
app.use(index);

const server = http.createServer(app);
const io = socketIo(server);

io.on("connection", socket => {
  console.log("New client connected"), setInterval(
    () => getApiAndEmit(socket),
    10000
  );
  socket.on("disconnect", () => console.log("Client disconnected"));
});

const getApiAndEmit = async socket => {
  try {
    const res = await axios.get(
      "https://api.darksky.net/forecast/PUT_YOUR_API_KEY_HERE/43.7695,11.2558"
    );
    socket.emit("FromAPI", res.data.currently.temperature);
  } catch (error) {
    console.error(`Error: ${error.code}`);
  }
};

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

We can test our server by starting the application with:

node app.js

As soon as the server starts you’ll see the following output:

Listening on port 4001

which confirms that everything is working fine.

Making use of our realtime server: the React client

Now that we have our tiny real-time server in place it’s time to make sense of our data. We want to display the current temperature in Florence and we will use React to get the job done.

Why? Because React does exactly what its name implies: it reacts to state changes. Our server will emit a message containing the current temperature which will be updated every 10 seconds.

React can store the temperature value inside a component’s state and render only the piece of text subject to changes.

If it’s your first time with React, install create-react-app to get started quickly by running:

npm i -g create-react-app

Then create the React application by running:

create-react-app socket-io-client

move inside the newly created directory:

cd socket-io-client

and install the Socket.IO client:

npm i socket.io-client

finally start the development React server:

npm start

To keep things simple we will just use the App.js component which lies inside the src directory.

Open up App.js. You can safely remove all the content inside the file and replace the code with the following:

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

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

  componentDidMount() {
    const { endpoint } = this.state;
    const socket = socketIOClient(endpoint);
    socket.on("FromAPI", data => this.setState({ response: data }));
  }

  render() {
    const { response } = this.state;
    return (
      <div style={{ textAlign: "center" }}>
        {response
          ? <p>
              The temperature in Florence is: {response} °F
            </p>
          : <p>Loading...</p>}
      </div>
    );
  }
}

export default App;

now point your browser to http://localhost:3000 and wait 10 seconds. You should see the following output (I’ve added some styling to my component, feel free to add some CSS to your App.js too):

Socket.IO and React paired together

If you keep an eye on the page you’ll notice the temperature changing over time, every 10 seconds.

It’s the magic of Socket.IO: as soon as the React component gets mounted, the componentDidMount creates a new connection to our Socket.IO server by instantiating a new socket:

const socket = socketIOClient(endpoint);

If you remember, the socket is a communication channel and we’re able to listen for any event happening inside it:

socket.on("FromAPI", data => this.setState({ response: data }));

If you take a look at the server-side code, the “FromAPI” message/event gets fired as soon as a new client connects to the server.

The client can listen for the event with the on() method and do something with the data contained inside the message/event. In our case we simply want to store the temperature inside our component’ store.

That’s it! Once established, the connection will receive the updates from the server without any need to refresh the page!

Where to go from here

Even if our example was quite basic, it should be clear how Socket.IO is not only suitable for instant messaging but also for a vaste range of purposes: the limit is only in our creativity.

I suggest exploring the Socket.IO’s documentation to learn more about Rooms, Namespaces and other API methods: Socket.IO Docs

Also, a good understanding of the Node.js event-driven architecture will be useful for mastering Socket.IO: start with the official docs and take a look at Understanding Node.js Event-Driven Architecture as well.

Thanks for reading!

Valentino Gagliardi

Valentino Gagliardi

Consultant, Developer Coach. Are you stuck on a project? Let's talk!
Valentino Gagliardi

27 Replies to “Going real time with Socket.IO, Node.Js and React”

    1. I there! A Node.JS application could definitively work on a shared server but you’ll be limited in terms of resources. Also, you won’t be able to run the application on startup with let’s say, PM2. A Virtual Private Server would be a better home for your application.

  1. Thanks for great delivery. your tutorial make us easy to follow and practice without unnecessary gimmick language found on others tutorial these days. 🙂 can we access this with react native webview ?

    1. Hi there! So here is the problem: my very first example sets a timeout every time a new user connects.

      That means the underlying API will be called endlessly unless you stop the program.

      That’s far from optimal. The timeout id must be stored inside a variable. From there you can clear the interval every time a user disconnects.

      Hope it makes sense.

      Cheers!

      1. Thanks for your reply,
        i’m new to node.js

        and my questions is – so why you didn’t clear the interval on the “disconnect” event ?

        1. Because I didn’t want to overcomplicate the code. I write my articles with beginners in mind and I want them to be as simple as possibile.

          But yes, I should have cleared that interval.

          Take a look here. Scroll down to the paragraph “IMPORTANT: As pointed out by some fellow readers, the code above has a flaw” and you’ll find an example of clearing the interval on disconnect.

          1. thanks for the reply.
            but i noticed that after someone close the browser and the “disconnect” event is emited – the interval keep working (even if i set he clear interval function in the “disconnect” event)

            is there away to prevent the interval from running when no client is assigned anymore ?

  2. ok i found the right way – i just created associative array with the key of the socket.id and assigned each of the interval to the right socket.id and that how i managed it

  3. Hi, I am getting this error, Please help!

    const getApiAndEmit = async socket => {
    ^^^^^^

    SyntaxError: Unexpected identifier

    1. I got my answer, actually, my node version was old which wasn’t supporting the ‘async’ syntax.
      Thanks for this article, hope to see some similar one in future. 🙂

  4. thanx very much for this 🙂
    but stupid question here.

    why cant i emit to specific sokcet.id like below:
    socket.to(socket.id).emit(“FromAPI”, res.data.currently.temperature);

  5. Hi, Thanks a lot, that was very helpful.
    I’m new to sockets and I used them for my react native app… when I create the server on my local machine everything works great and the app is able to reach the server and communicate. However, when I deployed the server on my Azure VM, the app just cannot reach it, the server can be reached from the browser so I don’t think it’s a server issue. but is there a unique way to build sockets for remote servers??
    Any help would be great… thanks in advance

  6. Perfect!

    Thank you so much.

    Just a question, is there any other way of emitting data continuously without the setInterval method?

    Thank you again!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.