📜 ⬆️ ⬇️

Solid RealTime on React and Socket.io

Today we will talk about how to adjust the interaction of a React application with a server using Socket.io, while achieving a high speed of application response to events generated by the server. Code examples are designed for React or React Native. At the same time, the concepts outlined here are universal, they can also be applied when developing using other frontend frameworks, such as Vue or Angular.

image

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 such a scenario, the server transmits fresh data to the client as it becomes available. After a connection is established between the client and the server, the server, without relying on client requests, initiates the transfer of data on its own.

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 in order to increase the speed of the response of the system, while the system itself can function without it. The motives of the developer in this case are not important. We believe it is acceptable to assume that you are reading this, since you would like to learn how to use sockets when creating React-applications and bring your development closer to real-time applications.
')
Here we will show a very simple example. Namely, we will create a server on Node.js, which can receive connections from clients written in React, and send to the socket, at a specified frequency, information about the current time. The client, receiving the latest data, will display them on the application page. Both the client and server use the Socket.io library.

Setting up the working environment


It is assumed that you have installed basic tools, such as Node.js and NPM. In addition, you will need the create-react-app NPM package, 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 socket-timer React application with which we will experiment by running the following command:

 create-react-app socket-timer 

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

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

Socket.io on server


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

 npm i --save socket.io 

Now create the server.js file in the root of the folder. In this file, first, import the library and create a socket:

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

Now you can use the io variable for working with sockets. Web sockets are long-lived two-way communication channels between the client and the 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.

Do the following:

 io.on('connection', (client) => { //       }); 

Next, you need to tell Socket.io about which port you want to expect to connect to the client.

 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 node server command. If everything is done correctly, you will see a message about its successful launch: listening on port 8000 .

Now the server is idle. Access to the channel of communication with the client is available, but the channel is still idle. The communication channel is two-way; therefore, the server can not only transmit data to the client, but also respond to events that the client generates. This mechanism can be viewed as a server event handler associated with a specific event of a specific client.

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

Edit the code in server.js as follows:

 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 handling a timer start event coming from a 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, bringing it to this view:

 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 start waiting 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 the subscribeToTimer event, which was generated on the client. The server, when received, starts a timer at the interval specified by the client. When the timer is triggered, the timer event is passed to the client.

At the moment, the code in the server.js file should 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 proceeding to the client, we will check whether, after all revisions, the server code is launched by running the node server command in the terminal. If, while you were editing server.js , the server was started, restart it to check the functionality of the latest changes.

Socket.io on the client


We have already started the React application by executing the npm start command in the terminal. If it is still running, open in the browser, then you can make changes to the code and the browser will immediately reload 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 the subscribeToTimer event and consuming the timer events that the server publishes.

To do this, create an api.js file in the src folder. In this file, we will create a function that can be called to send the server a subscribeToTimer event and send the timer event data generated by the server to 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 Node.js style, 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 library Socket.io. This can be done from the terminal:

 npm i --save socket.io-client 

Next - import the library. Here we can use the syntax of the ES6 modules, since the client code being executed is transpiled using Webpack and Babel. You can create a socket by calling the main export function from the socket.io-client module and transferring server information 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 for the subscribeToTimer event, after receiving which we will start the timer, and each time it is triggered, we will generate timer events sent to the client.

Now it only remains to subscribe to the timer event coming from the server and generate the event subscribeToTimer . Each time, receiving a timer event from the server, we will perform a callback function with the event data. As a result, the full code of api.js will 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 }; 

Note that we subscribe to the socket's timer event before we generate the subscribeToTimer event. This is done in case we encounter a race condition when the server has already started issuing timer events and the client has not yet signed for 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 api.js file api.js ready, 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 using the create-react-app file, the App.js file was generated (in the src folder). 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 to the same file the component constructor, inside of which you can call the function subscribeToTimer from api.js Every time, receiving an event from the server, simply write the value of the timestamp to the component state, using the data that came from the server.

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

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

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

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

 render() { return (   <div className="App">     <p className="App-intro">     This is the timer value: {this.state.timestamp}     </p>   </div> ); } 

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

Results


I often use the pattern of interaction between the server and client code described here. You can easily extend it for use in your own scripts. Hopefully, now everyone who wants to bring their React development closer to real-time applications will be able to do it.

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

Source: https://habr.com/ru/post/333618/


All Articles