Create a realtime chat app with React hooks, socket.io and NodeJS
Tags: react, nodejs, socketio, reactnative
Published: 2021-07-27 22:29:15

---
description: Learn how to develop a real-time chat application with React Hooks, Socket.IO, WebSockets, React Native, ExpressJS and NodeJS.
canonical_url: https://deepinder.me/creating-a-real-time-chat-application-with-react-hooks-socket-io-and-nodejs
---
In this tutorial, we'll learn how to build a real-time chat application with React Hooks, Socket.IO, WebSockets, ExpressJS and NodeJS. This would also work with React Native.

This might be the most searched query among all developers on how to make a live chat application with `React` and `Socket.io` .We will be using expressJS on top of NodeJS as a backend.

> Read more of these stories on my [website](https://deepinder.me).

### Creating a NodeJS Express App

Let’s start by creating a `nodejs` project first.

Create a new `directory` and then enter it.

    mkdir socketio-node

This will create a empty folder with name `socketio-node`.

We’re going to use the Node.JS web framework `expressJS`. Make sure [NodeJS](https://nodejs.org/) is installed on your system.

First let’s create a `package.json` manifest file that describes our project.
Create a file named package.json and paste the below code into it.(You can also do it with `npm init`)

    {  
    	"name": "socketio-node",
        "version": "0.0.1",
    	"description": "my first socket.io app",
        "dependencies": {}
    }

Now, in order to easily populate the `dependencies` property we need to install `express`, type this in the terminal.

    npm install express

It will install and add the latest version of express into our project and your `dependencies` will now look like. The version can be different depending on the latest version at the time you install it.

    "dependencies": {
      "express": "^4.17.1"
    }

Now that express is installed we can create an `index.js` file that will setup our application.

    const app = require('express')();
    const http = require('http').createServer(app);
    
    app.get('/', (req, res) => {
      res.send('<h1>Hey Socket.io</h1>');
    });
    
    http.listen(3000, () => {
      console.log('listening on *:3000');
    });

This code is explained in the following steps:

- Express initializes `app` to be a function handler that you can supply to an HTTP server (as seen in line 2).
- We define a route handler `/` that gets called when we hit our website home.
- We make the http server listen on port 3000.

If you run `node index.js` you should see the following:
![node server listening on port 3000](https://res.cloudinary.com/deepinder/image/upload/w_600,h_400,c_fit,dpr_2.0/blog/1_BL3MXnEZKZmq6-kPQp-9Xw.png)node server listening on port 3000

Opening [http://localhost:3000](http://localhost:3000/) in browser would look like:
![node server serving html on 3000](https://res.cloudinary.com/deepinder/image/upload/w_600,h_400,c_fit,dpr_2.0/blog/1_xaoZXJEsstsrdKTFhVs0vA.png)
### Integrating Socket.io with NodeJS

Now let’s integrate socket.io into our node app. Firstly, we need to install `socket.io` dependency into our app. Run this in the terminal.

    npm install socket.io

This will install the module and add the dependency to `package.json`. Now let’s edit `index.js` to add it:

    const app = require('express')();
    const http = require('http').createServer(app);
    const io = require('socket.io')(http, {
      cors: {
        origins: ['http://localhost:3001']
      }
    });
    
    app.get('/', (req, res) => {
      res.send('<h1>Hey Socket.io</h1>');
    });
    
    io.on('connection', (socket) => {
      console.log('a user connected');
      socket.on('disconnect', () => {
        console.log('user disconnected');
      });
    });
    
    http.listen(3000, () => {
      console.log('listening on *:3000');
    });

Notice that I initialize a new instance of `socket.io` on line 3 by passing the `http` (the HTTP server) object and the cors options(updated for socket.io v3) to allow our react localhost url, you can put in the url or your frontend client, in my case it was `localhost:3001`
Then I listen on the `connection` and `disconnection` events for incoming sockets, and I log it to the console.

Our Backend is good to go for now, we will come back to our `node` code when we will implement more events further on.

### Creating a React app

Let’s start by creating an `React` app now. I will be creating a new `React` app from scratch with `create-react-app`, while most of you would already have one created with you.
Those who already have a working `React` app can skip the following code:

    npx create-react-app socketio-react

*([npx](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b) comes with npm 5.2+ and higher, see [instructions for older npm versions](https://gist.github.com/gaearon/4064d3c23a77c74a3614c498a8bb1c5f))*
This would install the latest version of `CRA` and create a new template React app from scratch.

Now let’s add socket.io `dependency` in our React app.

    cd socketio-react
    npm install socket.io-client

This would install the latest `socket.io-client` library in our React app.

### Creating a socket client service

Now let’s start by creating a `file` to handle socket.io connection. I would create a root level file named `socketio.service.js` and include that in the `src` folder.

You can create the file by running the following command.

    cd src
    touch socketio.service.js

This would create a file named socketio.service.js . The directory structure would look something like this. This is just a simple one page demo, so i added the file into the src folder like this.
![file structure of project](https://res.cloudinary.com/deepinder/image/upload/w_600,h_400,c_fit,dpr_2.0/blog/Screenshot-2021-02-15-at-2.20.56-AM-1.png)
Now, go into the `socketio.service.js` file and import the following:

    import { io } from 'socket.io-client';

Now let’s add the socket endpoint/url that we would connect the socket.io client to the backend. We will start by creating a .env file in the root of the folder which would our environment variables.

    touch .env

![.env file location](https://res.cloudinary.com/deepinder/image/upload/w_600,h_400,c_fit,dpr_2.0/blog/Screenshot-2021-02-15-at-2.23.58-AM-3.png)
We will add the following url in `.env` file

    REACT_APP_SOCKET_ENDPOINT=http://localhost:3000

We have to write `REACT_APP` as a prefix as it is needed by `create-react-app`. For more details you can check this [link](https://create-react-app.dev/docs/adding-custom-environment-variables/).

Let's start by writing our `socketio.service.js` and write a socket init function.

    import { io } from 'socket.io-client';
    
    let socket;
    
    export const initiateSocketConnection = () => {
    	socket = io(process.env.REACT_APP_SOCKET_ENDPOINT);
    	console.log(`Connecting socket...`);
    }

This will declare a variable named `socket` and then after calling the `initiateSocketConnection` function, `socket` connect would be initialized on the `URL` provided in `.env` file and `socket` variable would be containing the connected socket object.

We have to use the variables inside `.env` file like this `process.env.yourvariablename`.

Since we have created a function, let's call it from our Component.

Start by opening `App.js` file and lets make use of the hooks. We will use `useEffect`hook which would only run once on render since we have to init the socket connection only once.

    import { useEffect } from 'react';
    
    function App() {
    
      useEffect(() => {
        initiateSocketConnection();
      }, []);
    
    }

Doing this would create a socket connection only once on component render and create our connection.

> *Note*: I am importing only { useEffect } from 'react'; but not import React, {useEffect} from 'react'; since i am on React 17 and it doesn't need that, if you are on old versions(< 17) you might end up importing the last one.

We will run the React app now using

    PORT=3001 npm start

I used port prefix 3001 as CRA runs on 3000 by default and NodeJS is also running on that port.
You can see the socket connected and our node app console showing `a user connected` when we open our browser tab running the React app
![logging of nodejs server](https://res.cloudinary.com/deepinder/image/upload/w_600,h_400,c_fit,dpr_2.0/blog/1_CLVOixL-yyE4Yg5h8zHH4A--1-.png)
### Disconnection

Now, let's try to disconnect the socket, we will use the cleanup function of the hooks.

    import { useEffect } from 'react';
    
    function App() {
    
      useEffect(() => {
        initiateSocketConnection();
        return () => {
          disconnectSocket();
        }
      }, []);
    
    }

In your `socketio.service.js` file add this for disconnection

    export const disconnectSocket = () => {
      console.log('Disconnecting socket...');
      if(socket) socket.disconnect();
    }

This will disconnect our socket as soon as the component gets destroyed. Also, the socket would get disconnected when we close the tab automatically, whether we handle it here or not, tab closing is handled by default.

When you disconnect the socket or close the webpage, you can see `user disconnected` message on console.

With this, we have completed our initialization and disconnection of sockets. Now we will learn about how to emit and listen to events.

### Event Handling

Let’s register an event called `my message` inside our `index.js` node file and console the data and we will emit the same event from `React` app.

    io.on('connection', (socket) => {
      
      console.log('a user connected');
      
      socket.on('disconnect', () => {
        console.log('user disconnected');
      });
      
      socket.on('my message', (msg) => {
        console.log('message: ' + msg);
      });
    });
    

And let’s emit the same event from React code in socket.service.js

    export const subscribeToChat = (cb) => {
    	socket.emit('my message', 'Hello there from React.');
    }

We will call this function from `useEffect` where we initialized our socket connection in App.js

    useEffect(() => {
        initiateSocketConnection();
        subscribeToChat((err, data) => {
          console.log(data);
        });
        return () => {
          disconnectSocket();
        }
      }, []);

This code would emit the event named `my message` and it would print the following on our node console. You can see the message ‘Hello there from React’. Our custom events are now working.
![message from react on node server](https://res.cloudinary.com/deepinder/image/upload/w_600,h_400,c_fit,dpr_2.0/blog/Screenshot-2021-02-16-at-8.45.11-PM.png)
### Broadcasting Event

Now, let’s `emit` an event from the `server side` to client side. We will broadcast the event to all connected users. We will broadcast the same message that we received from client and prepend a server string to it.

    io.on('connection', (socket) => {
      socket.on('my message', (msg) => {
        io.emit('my broadcast', `server: ${msg}`);
      });
    });

This would emit the message received to all connected sockets.

Let’s add an listener for `my broadcast` event on our `React` app now.

    export const subscribeToChat = (cb) => {
    	socket.emit('my message', 'Hello there from React.');
    
        socket.on('my broadcast', msg => {
        	return cb(null, msg);
        });
    }

Here, we receive the `my broadcast` event and call the registered callback in App.js
Since we already had a console.log written in App.js subscription, it will print the message received from server.

You can check your `browser console`, it would `print` something like this. It prints a message from server, that emitted the broadcast.
![view of react app in browser](https://res.cloudinary.com/deepinder/image/upload/w_600,h_400,c_fit,dpr_2.0/blog/Screenshot-2021-02-16-at-4.53.44-PM-1.png)
We have covered the `basic` parts of connecting an node socket.io app with an React app.

### BONUS: Authentication

You can also send `authentication parameters` to the Backend when connecting to the socket by using `auth` object in options in a connection.

    export const initiateSocketConnection = (room) => {
    	socket = io(process.env.REACT_APP_SOCKET_ENDPOINT, {
    	  auth: {
    	    token: 'cde'
    	  },
    	});
    	console.log(`Connecting socket...`);
    }

I am sending token key here. You can use any key you want, to provide auth token or any other key.

To `fetch` this information on the Backend, we have to do it like this:

    io.on('connection', (socket) => {
      let token = socket.handshake.auth.token;
    });

This would return the value `cde` passed by Frontend.

> You can check all of the above written example code at my [github](https://github.com/deepinder10/socketio-example).

This concludes my article about creating a `real time application` with `React` and `Socket.io` with `NodeJS` and `ExpressJS`.

> The next part of this article which explains the concept of rooms, realtime one to one chat and group chat is [here](https://deepinder.me/create-a-realtime-chat-app-with-react-hooks-socket-io-rooms-part-2).

Do write down your reviews and remember to [subscribe](https://buttondown.email/deepinder) for more content like this.

> Read more of these stories on my [website](https://deepinder.me).

Liked my work? Buy me a [coffee](https://paypal.me/iamdeepinder).