In this article we are going to create a real time chat application with reactjs, socket.io and Expressjs
Let us start building the application
Pre-requisites You need to have basic knowledge of these technologies.
ReactJs Socket.io NodeJs JavaScript Installation Create a new directory called the react-chat-app
and cd in the it. Then type the below command to initialize a new project
npm init
This would ask you a few basic questions and create an package.json
file
initializing the application Now, type the below code to install the dependencies
npm install react react-dom socket.io socket.io-client express --save
installing required dependencies Now the package.Json should look something like this:
{
"name": "react-chat-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "DeadSimpleChat Team",
"license": "ISC",
"dependencies": {
"express": "^4.18.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"socket.io": "^4.6.1",
"socket.io-client": "^4.6.1"
}
}
package.json Now we have installed everything we need. Let us start coding
Creating the Server In the root folder create a file and name it index.js and open the folder in your favorite text editor. I am using visual studio code.
Then in the index.js paste the following code
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const path = require('path');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const PORT = process.env.PORT || 4000;
app.get('/', (req, res) => {
res.send('Hello World!')
});
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
index.js What are we doing here
We are importing the required modules for our application namely: express, http, socketIO
and path We are creating an HTTP
server with express Then we are initializing socket.io
on the HTTP
server and defining a port to listen on Then we are creating a get route and sending Hello world when you go to localhost://4000
You can go to localhost:4000 and you will see there the hello world. Till now we have created a http server and initialized an socket.io instance on it
localhost 4000 '
Create the public folder Let us now create a folder in the root and name it public and we will write code to render it using express.static
middleware. Write this code in your index.js
app.use(express.static(path.join(__dirname, 'public')));
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const path = require('path');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const PORT = process.env.PORT || 4000;
app.use(express.static(path.join(__dirname, 'public')));
app.get('/', (req, res) => {
res.send('Hello World!')
});
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
index.js Creating HTML file Now create a file in your public folder and name it index.html and write the below code there
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Socket.IO Chat</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/socket.io-client@4/dist/socket.io.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel" src="/client/client.js"></script>
</body>
</html>
index.html What are we doing here
we are adding all the dependencies for the front end code though CDN
. you can choose to npm
install these as well then just above the closing body tag we are including the client.js file.
Creating the client.js file Let us next create the client.js file
Now, create another folder in the root and call it client and create a file inside the client folder and name it client.js
Open the client .js file and paste the below code there
// client/client.js
const { useState, useEffect } = React;
const { io } = window;
const SOCKET_SERVER_URL = 'http://localhost:4000';
const App = () => {
const [message, setMessage] = useState('');
const [messages, setMessages] = useState([]);
const [socket, setSocket] = useState(null);
useEffect(() => {
const newSocket = io(SOCKET_SERVER_URL);
setSocket(newSocket);
newSocket.on('chat message', (msg) => {
setMessages((prevMessages) => [...prevMessages, msg]);
});
return () => {
newSocket.disconnect();
};
}, []);
const handleMessageChange = (e) => {
setMessage(e.target.value);
};
const handleSendMessage = (e) => {
e.preventDefault();
if (message.trim()) {
socket.emit('chat message', message);
setMessage('');
}
};
return (
<div>
<h1>React Socket.IO Chat</h1>
<ul>
{messages.map((msg, i) => (
<li key={i}>{msg}</li>
))}
</ul>
<form onSubmit={handleSendMessage}>
<input
type="text"
value={message}
onChange={handleMessageChange}
placeholder="Start typing the message"
/>
<button type="submit">Send Message</button>
</form>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
client.js What are we doing here
We are importing the required dependencies these include the useState and useEffect from React and Socket.io client side library Then we are declaring the socket server url to be 4000 After that we are creating the App component We are declaring the variables for current message, message list and socket We are using the useEffect to listen to the socket server url and setting up listeners for the incoming sockets Creating a function to take the input form the front end and Create a function to send the message to the server Then we come to the return function Setting up basic HTML and declaring the H1 rendering the messages in a list creating a form to take the messge input form the user and calling the handleMessageChange
function Lastly let us edit the index.js file and add the following code
app.get('/client/client.js', (req, res) => {
res.sendFile(path.join(__dirname, 'client', 'client.js'));
});
and delete the default get route which sent the 'Hello world'
// Delete this code
app.get('/', (req, res) => {
res.send('Hello World!')
});
Also write the code to handle socket.io connections in the index.js file
io.on('connection', (socket) => {
console.log('A user connected');
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
handle socket.io connections The completed index.js
file looks like:
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const path = require('path');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const PORT = process.env.PORT || 4000;
app.use(express.static(path.join(__dirname, 'public')));
app.get('/client/client.js', (req, res) => {
res.sendFile(path.join(__dirname, 'client', 'client.js'));
});
io.on('connection', (socket) => {
console.log('A user connected');
socket.on('chat message', (msg) => {
io.emit('chat message', msg);
});
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
index.js Now we have completed the app the app looks like this
completed app You can open the app in multiple browser windows and send the messages in real time and they would appear like
App sending messages This is a simple demonstration, you can add styling to it and make it look good.
Bonus As a bonus feature let us add a feature to show usernames of the user sending the message
In the index.js update the code to include the message senders username
socket.on('chat message', ({ username, message }) => {
io.emit('chat message', { username, message });
});
index.js The complete index.js code looks like
const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const path = require('path');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const PORT = process.env.PORT || 5000;
app.use(express.static(path.join(__dirname, 'public')));
app.get('/client/index.js', (req, res) => {
res.sendFile(path.join(__dirname, 'client', 'index.js'));
});
io.on('connection', (socket) => {
console.log('A user connected');
socket.on('chat message', ({username, message}) => {
io.emit('chat message', {username, message});
});
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
index.js On the client side let us update the code and add a new state variable to store the username of the sender.
const [username, setUsername] = useState('');
and add an input field inside the form to enable the user to create a username
<form onSubmit={handleSendMessage}>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="enter/create a username"
/>
<input
type="text"
value={message}
onChange={handleMessageChange}
placeholder="Start typing the message"
/>
<button type="submit">Send Message</button>
</form>
client.js Now, edit the handle message function to include the username when sending the message to the user
const handleSendMessage = (e) => {
e.preventDefault();
if (message.trim() && username.trim()) {
socket.emit('chat message', { username, message });
setMessage('');
}
};
client.js Lastly edit the list code to show the username of the user sending the message
<ul>
{messages.map((msg, i) => (
<li key={i}>
<strong>{msg.username}: </strong>
{msg.message}</li>
))}
</ul>
index Here is what the app looks like:
Completed Chat application You might be interested in some of our other articles
Conclusion In this article we made a group chat application with react and socket.io and express and Nodejs
We made a group chat application and as a bonus feature we added the username of the user sending the message
Thanks for reading. Below is the complete code for the application
Complete Code Here is the complete code for the application
Index.js const express = require('express');
const http = require('http');
const socketIO = require('socket.io');
const path = require('path');
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
const PORT = process.env.PORT || 4000;
app.use(express.static(path.join(__dirname, 'public')));
app.get('/client/client.js', (req, res) => {
res.sendFile(path.join(__dirname, 'client', 'client.js'));
});
io.on('connection', (socket) => {
console.log('A user connected');
socket.on('chat message', ({username, message}) => {
io.emit('chat message', {username, message});
});
socket.on('disconnect', () => {
console.log('A user disconnected');
});
});
server.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});
index.js Client.js const { useState, useEffect } = React;
const { io } = window;
const SOCKET_SERVER_URL = 'http://localhost:4000';
const App = () => {
const [message, setMessage] = useState('');
const [messages, setMessages] = useState([]);
const [socket, setSocket] = useState(null);
const [username, setUsername] = useState('');
useEffect(() => {
const newSocket = io(SOCKET_SERVER_URL);
setSocket(newSocket);
newSocket.on('chat message', (msg) => {
setMessages((prevMessages) => [...prevMessages, msg]);
});
return () => {
newSocket.disconnect();
};
}, []);
const handleMessageChange = (e) => {
setMessage(e.target.value);
};
const handleSendMessage = (e) => {
e.preventDefault();
if (message.trim() && username.trim()) {
socket.emit('chat message', { username, message });
setMessage('');
}
};
return (
<div>
<h1>React Socket.IO Chat</h1>
<ul>
{messages.map((msg, i) => (
<li key={i}>
<strong>{msg.username}: </strong>
{msg.message}</li>
))}
</ul>
<form onSubmit={handleSendMessage}>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="enter/create a username"
/>
<input
type="text"
value={message}
onChange={handleMessageChange}
placeholder="Start typing the message"
/>
<button type="submit">Send Message</button>
</form>
</div>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
client.js Index.html <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>React Socket.IO Chat</title>
</head>
<body>
<div id="root"></div>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/socket.io-client@4/dist/socket.io.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel" src="/client/client.js"></script>
</body>
</html>
index.html package.json
{
"name": "react-chat-app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "DeadSimpleChat Team",
"license": "ISC",
"dependencies": {
"express": "^4.18.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"socket.io": "^4.6.1",
"socket.io-client": "^4.6.1"
}
}
package.json