Solid realtime on React and Socket.io

Original author: Hendrik Swanepoel
  • Transfer
Today we’ll talk about how to establish interaction between a React application and a server using Socket.io, while achieving a high response speed of the application to events that the server generates. Code examples are designed for React or React Native. At the same time, the concepts presented here are universal, they can be applied when developing using other front-end frameworks, such as Vue or Angular. So, we need the client application to respond to events generated on the server. Usually in such cases we are talking about real-time applications. In this scenario, the server sends the client fresh data as it appears. After a connection is established between the client and the server, the server, without relying on client requests, independently initiates data transfer.

image



This model is suitable for many projects. Among them are chats, games, trading systems, and so on. Often, the approach proposed in this material is used to increase the response rate of a system, despite the fact that such a system itself can function without it. The motives of the developer are not important in this case. We assume that it’s permissible to assume that you are reading this, as you would like to learn about how to use sockets to create React applications and bring your development closer to real-time applications.

Here we show a very simple example. Namely, we will create a server on Node.js, which can accept connections from clients written in React and send information about the current time to the socket, with the specified frequency. The client, receiving the latest data, will display it on the application page. Both the client and server use the Socket.io library.

Setting up the work environment


It is assumed that you have installed basic tools such as Node.js and NPM. In addition, you will need an NPM package create-react-app, so if you do not already have it, install it globally with this command:

npm --global i create-react-app

Now you can create a React application socket-timerwith which we will experiment by running the following command:

create-react-app socket-timer

Now prepare your favorite text editor and find the folder in which the application files are located socket-timer. In order to start it, it is enough to execute, using the terminal, a command npm start.

In our example, the server and client code will be located in the same folder, but this should not be done in working projects.

Socket.io on the server


Create a server that supports web sockets. In order to do this, go to the terminal, switch to the application folder and install Socket.io:

npm i --save socket.io

Now create a file server.jsin the root of the folder. In this file, for starters, import the library and create a socket:

const io = require('socket.io')();

Now you can use a variable ioto work with sockets. Web sockets are long-lived two-way communication channels between a client and a server. On the server, you must accept the connection request from the client and maintain the connection. Using this connection, the server will be able to publish (generate) events that the client will receive.

We do the following:

io.on('connection', (client) => {
  // тут можно генерировать события для клиента
});

Next, you need to tell Socket.io on which port you want to wait for the client to connect.

const port = 8000;
io.listen(port);
console.log('listening on port ', port);

At this stage, you can go to the terminal and start the server by running the command node server. If done correctly, you will see a message about its successful launch: listening on port 8000.

The server is idle now. Access to the communication channel with the client is available, but the channel is still idle. The communication channel is two-way, so the server can not only transmit data to the client, but also respond to events that the client generates. This mechanism can be considered as a server-side event handler attached to a specific event of a particular client.

In order to complete work on the server part of the application, you need to start the timer. It is necessary that the service starts a new timer for each client connecting to it, while it is necessary that the client can transmit information to the server about the interval with which it wants to receive data. This is an important point, demonstrating the possibilities of two-way communication between the client and server.

Edit the code in server.jsthe following way:

io.on('connection', (client) => {
  client.on('subscribeToTimer', (interval) => {
    console.log('client is subscribing to timer with interval ', interval);
  });
});

Now we have a basic design for organizing a client connection and for processing a timer start event coming from the client. Now you can start the timer and start broadcasting events containing information about the current time to the client. Edit the server code again to make it look like this:

io.on('connection', (client) => {
  client.on('subscribeToTimer', (interval) => {
    console.log('client is subscribing to timer with interval ', interval);
    setInterval(() => {
      client.emit('timer', new Date());
    }, interval);
  });
});

Here we open the socket and begin to wait for clients to connect. When a client connects, we find ourselves in a closure where we can handle events from a particular client. In particular, we are talking about an event subscribeToTimerthat was generated on the client. The server, upon receipt, starts the timer at the interval specified by the client. When the timer is triggered, the event is timersent to the client.

At the moment, the code in the file server.jsshould look like this:

const io = require('socket.io')();
io.on('connection', (client) => {
  client.on('subscribeToTimer', (interval) => {
    console.log('client is subscribing to timer with interval ', interval);
    setInterval(() => {
      client.emit('timer', new Date());
    }, interval);
  });
});
const port = 8000;
io.listen(port);
console.log('listening on port ', port);

The server part of the project is ready. Before moving to the client, we will check to see if, after all the edits, the server code is launched by executing the command in the terminal node server. If, while you were editing server.js, the server was running, restart it to check the health of the latest changes.

Socket.io on the client


We already launched the React application by executing a command in the terminal npm start. If it is still running, open in the browser, then you can make changes to the code and the browser will immediately restart the modified application.

First, you need to write client code for working with sockets, which will interact with the server socket and start the timer, generating an event subscribeToTimerand consuming the events timerthat the server publishes.

To do this, create a file api.jsin a folder src. In this file we will create a function that can cause the server to send events subscribeToTimerand data events timergenerated by the server, the code that deals with the visualization.

Let's start by creating a function and exporting it from the module:

function subscribeToTimer(interval, cb) {
}
export { subscribeToTimer }

Here we use functions in the style of Node.js, where the one who calls the function can pass the timer interval in the first parameter, and the callback function in the second.

Now you need to install the client version of the Socket.io library. You can do this from the terminal:

npm i --save socket.io-client

Next - we import the library. Here we can use the syntax of ES6 modules, since the client-side code that is being executed is transposed using Webpack and Babel. You can create a socket by calling the main exported function from the module socket.io-clientand passing data about the server to it:

import openSocket from 'socket.io-client';
const socket = openSocket('http://localhost:8000');

So, on the server we are waiting for the client to connect and the event subscribeToTimer, after receiving which we will start the timer, and, each time it is triggered, we will generate events timerthat are sent to the client.

Now it remains only to subscribe to the event timercoming from the server and generate an event subscribeToTimer. Each time, receiving an event timerfrom the server, we will perform the callback function with the event data. As a result, the full code api.jswill look like this:

import openSocket from 'socket.io-client';
const  socket = openSocket('http://localhost:8000');
function subscribeToTimer(cb) {
  socket.on('timer', timestamp => cb(null, timestamp));
  socket.emit('subscribeToTimer', 1000);
}
export { subscribeToTimer };

Please note that we subscribe to the event timerof the socket before generate an event subscribeToTimer. This is done in case we are faced with the state of the races, when the server will already start issuing events timer, and the client has not yet subscribed to them, which will lead to the loss of data transmitted in the events.

Using data received from the server in the React component


So, the file is api.jsready, it exports a function that can be called to subscribe to events generated by the server. Now let's talk about how to use this function in the React component to output, in real time, data received from the server through a socket.

When creating a React application with the help of create-react-appa file was generated App.js(in the folder src). At the top of the code for this file, add the import of the previously created API:

import { subscribeToTimer } from './api';

Now you can add the component constructor to the same file, inside which you can call the function subscribeToTimerfrom api.js. Each time, receiving an event from the server, we simply write the value timestampto the state of the component, using the data received from the server.

constructor(props) {
  super(props);
  subscribeToTimer((err, timestamp) => this.setState({
    timestamp
  }));
}

Since we are going to use the value timestampin the state of the component, it makes sense to set the default value for it. To do this, add the following code snippet below the constructor:

state = {
  timestamp: 'no timestamp yet'
};

At this stage, you can edit the function code renderso that it displays the value timestamp:

render() {
  return (
    
     

     This is the timer value: {this.state.timestamp}      

   
 ); }

Now, if everything is done correctly, the current date and time received from the server will be displayed on the application page every second.

Summary


I often use the server-client code interaction pattern described here. You can easily expand it for use in your own scripts without too much difficulty. I would like to hope that now everyone who wanted to bring their React-developments closer to real-time applications will be able to do this.

Dear readers! Do you plan to apply the client-server interaction technique described here in your projects?

Also popular now: