How to Integrate Socket.IO with React 2021
Socket.IO is the popular javascript library that helps us to create a real-time web application. With the help of it, we can manage the real-time, bidirectional and event-based communication between two applications. It works on every platform, browser or device, focusing equally on reliability and speed.
"socket.io enables full-duplex communication between the client and server"
Implementation:
Frontend: react.js, socket.io-client
Backend: node.js (express), socket.io
Let's Start with Frontend.
1. Install create-react-app package.
npm i -g create-react-app
2. after installation create a new project.
create-react-app client //client is project name
3. Install socket.io-client package in your project.
cd client
npm i socket.io-client
4. Create a context folder inside the src folder. (using context we can reuse the io). after that create a file socket.js inside the context folder. add this code socket.js file.
import React from 'react';
import io from "socket.io-client";
export const socket = io(process.env.REACT_APP_SOCKET_URL, { transports: ['websocket'] });
export const SocketContext = React.createContext();
Don't forget to define REACT_APP_SOCKET_URL environment variable in .env file. After backend implementation, we will update this variable.
5. Now we need to wrap our app with SocketContext. so that all children are able to access this context. open App.js file.
import './App.css';
import { socket, SocketContext } from './context/socket';
function App() {
return (
<SocketContext.Provider value={socket}>
<div className="container">
</div>
</SocketContext.Provider>
);
}
export default App;
6. Create a component(ListComponent).
client/src/components/pages/movies/list.component.jsx
import React from 'react';
const ListComponent = () => {
return (
);
}
export default ListComponent;
7. Import SocketContext your component in App.js
import './App.css';
import ListComponent from './components/pages/movies/list.component';
import { socket, SocketContext } from './context/socket';
function App() {
return (
<SocketContext.Provider value={socket}>
<div className="container">
<ListComponent />
</div>
</SocketContext.Provider>
);
}
export default App;
8. Now import SocketContext in your component.
import React, { useContext, useEffect } from 'react';
import { SocketContext } from '../../../context/socket';
const ListComponent = () => {
const socket = useContext(SocketContext);
useEffect(() => {
// here we can use socket events and listeners
return () => socket.disconnect(); //cleanup
}, [])
return (
);
}
export default ListComponent;
Backend:-
1. Install express-generator package.
npm install -g express-generator
2. after installation create a new project.
express server --view=hbs //server is project name
Note:- you can use --no-view flag if you don't want to setup the view engine.
3. Install socket.io package in your project.
cd server
npm i socket.io
4. create a socket folder in your project. inside this folder create an index.js file. and add the following code.
module.exports = (io) => {
io.on('connection', socket => {
console.log('new connection');
socket.on('disconnect', () => console.log('disconnected'));
})
}
5. Now we need to attach io with the express server. so open app.js file. and import socket io and our socket handler. also, change the export statement as shown.
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
// require socket.io
const io = require('socket.io')(); //<------
require('./socket')(io) //<------
module.exports = { app, io }; //<------
6. so now our app.js module exporting two objects. that's why we need to modify www file. placed inside bin folder. see arrow in sample code
#!/usr/bin/env node
/**
* Module dependencies.
*/
var { app, io } = require('../app'); //<-------------
var debug = require('debug')('server:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3001'); //<-------------
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
/**
* Attach io with http server.
*/
io.attach(server); //<-------------
These three lines
var { app, io } = require('../app');
var port = normalizePort(process.env.PORT || '3001');
io.attach(server);
7. Now start your backend code
npm start
By default express code running on 3000. and our react project also using 3000 that's why we need to change backend port http://localhost:3001 open this url in the browser you will see express in the browser window.
Connect Backend with Frontend
1. Now in your frontend code open .env file and modify REACT_APP_SOCKET_URL
REACT_APP_SOCKET_URL=http://localhost:3001
2. Start the frontend project
npm start
open http://localhost:3000 on the browser and check node server terminal.
you will see a new connection message by our console.log statement.
so our socket connection established successfully. now we can use emit() and on() inside our component.
import React, { useContext, useEffect, useState } from 'react';
import { Col, Row } from 'reactstrap';
import { SocketContext } from '../../../context/socket';
import FormComponent from './form.component';
const ListComponent = () => {
const socket = useContext(SocketContext);
const [movies, setMovies] = useState([]);
const [movieDetail, setMovieDetail] = useState(null);
const [modal, setModal] = useState(false);
useEffect(() => {
socket.emit('fetchMovies');
socket.on('fetchMovies', setMovies);
return () => socket.disconnect();
}, [])
const handleModal = (movie) => {
if(movie) {
setMovieDetail(movie)
}
setModal(true);
}
const handleDelete = (movie) => {
socket.emit('deleteMovie', movie.id);
}
const handleClose = () => {
setModal(false);
setMovieDetail(null)
}
return (
<>
<Row>
<Col className="mb-1 mt-1 text-end" md={{ size: 8, offset: 2 }}>
<button className="btn btn-primary btn-sm" onClick={() => handleModal()}>Add Movie</button>
</Col>
</Row>
<Row>
<Col md={{ size: 8, offset: 2 }}>
<table className="table table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Category</th>
<th scope="col">Rating</th>
<th scope="col">Action</th>
</tr>
</thead>
<tbody>
{
movies.map((movie, i) => {
return (
<tr key={i}>
<th>{movie.id}</th>
<td>{movie.name}</td>
<td>{movie.category}</td>
<td><span className="badge bg-warning text-dark">{movie.rating}</span></td>
<td>
<button className="btn btn-primary btn-sm me-2" onClick={() => handleModal(movie)}>Edit</button>
<button className="btn btn-danger btn-sm" onClick={() => handleDelete(movie)}>Delete</button>
</td>
</tr>
)
})
}
</tbody>
</table>
{
modal
&&
<FormComponent
show={modal}
movie={movieDetail}
onClose={handleClose}
/>
}
</Col>
</Row>
</>
);
}
export default ListComponent;
Rooms:- https://socket.io/docs/v4/rooms
Emit Cheatsheet:- https://socket.io/docs/v4/emit-cheatsheet
Checkout my full Socket.IO CRUD example using mysql(sequelize).
https://github.com/ultimateakash/react-socket.io
If you need any help, don't hesitate to comment below.
Thanks.
Leave Your Comment