How to make chat-app with socket.io in reactjs?
Creating new applications using React and Node.js always requires a certain amount of work before you actually start working on the final solution. In this tutorial you will find everything you need to start from scratch. Develop a Chat Application Using React, Express and Socket.IO
Installing Node.js dependencies
In the begginning, we're going to use Express as the API that will handle every request made by the front-end:
Command is displayed below:
1npm --save express
After installing our core library we can proceed to create the Node file that will execute all the logic of our application. Create a index.js File in the root directory of your back-end project:
1const express = require("express");
2const app = express();
3const http = require("http");
4const server = http.createServer(app);
5const { Server } = require("socket.io");
6const io = new Server(server, {
7 cors: {
8 origin: "http://localhost:3000",
9 methods: ["*"],
10 },
11});
12
13app.get("/", (req, res) => {
14 res.sendFile(__dirname + "/index.html");
15});
16
17let users = [];
18let chat = [];
19const addUser = (user, socketId) => {
20 !users.some((item) => item.user.id === user.id) && users.push({ user, socketId });
21};
22
23const removeUser = (socketId) => {
24 users = users.filter((user) => user.socketId !== socketId);
25};
26
27const logoutUser = (id) => {
28 users = users.filter((item) => item.user.id !== id);
29};
30
31
32io.on("connection", (socket) => {
33 //when ceonnect
34 console.log("a user connected.");
35 socket.join(socket.id);
36 //take userId and socketId from user
37 socket.on("addUser", (user) => {
38 addUser(user, socket.id);
39 io.emit("getUsers", users);
40 });
41
42 socket.on("logout", (userId) => {
43 logoutUser(userId);
44 io.emit("getUsers", users);
45 });
46
47 //get chat of single user
48 socket.on("getChat", ({ recieverId, senderId }) => {
49 let selectedUserChat = chat.filter((item) => {
50 if (
51 (item.recieverId === recieverId && item.senderId === senderId) ||
52 (item.recieverId === senderId && item.senderId === recieverId)
53 ) {
54 return item;
55 }
56 });
57 let user = users.find((item) => item.user.id === senderId);
58 io.to(user.socketId).emit("chat", selectedUserChat);
59 });
60
61 //send and get message
62 socket.on("sendMessage", (data) => {
63 chat.push({
64 senderId: data.sender,
65 recieverId: data.reciever,
66 message: data.message,
67 });
68 // const user = getUser(data.reciever);
69 // io.to(user.socketId).emit("newMessage", {
70 // senderId: data.sender,
71 // recieverId: data.reciever,
72 // message: data.message,
73 // });
74 });
75
76 //when disconnect
77 socket.on("disconnect", () => {
78 console.log("A user disconnected!")
79 removeUser(socket.id);
80 io.emit("getUsers", users);
81 });
82});
83
84server.listen(5000, () => {
85 console.log("listening on *:5000");
86});
Creating the Front End The first step to create the front end of our applications will be to initialize the React application. You can easily do this with the command:
1npx create-react-app my-app
Now that the code base for react-app is initialized, we can proceed to install the Socket.IO library for our front end. Just use the client library of socket.io with:
1npm i socket.io-client
After installing the library ,we should have to code for front end.
1import React, { useState, useEffect } from "react";
2import io from "socket.io-client";
3import "./App.css";
4import user1ImgPath from "./images/user1.jfif";
5import user2ImgPath from "./images/user2.jfif";
6import { Card, Form, Button } from "react-bootstrap";
7const socket = io.connect("http://localhost:5000");
8function App() {
9 const [users, setUsers] = useState([]);
10 const [input, setInput] = useState("");
11 const [messages, setMessages] = useState([]);
12 const [reciever, setReciever] = useState("");
13 const [isLogedIn, setIsLogedIn] = useState(false);
14 const [logedInUser, setLogedInUser] = useState({
15 id: 0,
16 name: "",
17 });
18
19 //user login
20 let submitLogin = (e) => {
21 e.preventDefault();
22 if (logedInUser.name) {
23 let userId = Math.floor(Math.random() * 100);
24 let newUser = {
25 id: userId,
26 name: logedInUser.name,
27 imgPath: user2ImgPath,
28 };
29 socket.emit("addUser", newUser);
30 setLogedInUser({ ...logedInUser, id: userId });
31 setIsLogedIn(true);
32 }
33 };
34
35 //user logout
36 let userLogout = () => {
37 socket.emit("logout", logedInUser.id);
38 setIsLogedIn(false);
39 setLogedInUser({ id: 0, name: "" });
40 };
41
42 //change handler of login input field
43 let onChangeHandler = (e) => {
44 setLogedInUser({ ...logedInUser, name: e.target.value });
45 };
46
47 //get chat of specific user
48 let getChat = (recieverId, senderId) => {
49 setReciever(recieverId);
50 socket.emit("getChat", { recieverId, senderId });
51 };
52
53 //send message
54 let sendMessage = () => {
55 console.log(reciever, "sdsad", input);
56 if (reciever && input !== "")
57 socket.emit("sendMessage", {
58 reciever,
59 sender: logedInUser.id,
60 message: input,
61 });
62
63 setMessages([
64 ...messages,
65 { senderId: logedInUser.id, recieverId: reciever, message: input },
66 ]);
67 setInput("");
68 };
69
70 socket.on("getUsers", (users) => {
71 setUsers(users);
72 });
73 socket.on("getMessage", (msg) => {
74 setMessages((prev) => {
75 return [
76 ...prev,
77 {
78 senderId: msg.senderId,
79 senderName: msg.senderName,
80 message: msg.message,
81 },
82 ];
83 });
84 });
85
86 socket.on("newMessage", (msg) => {
87 setMessages((prev) => {
88 if (prev.length != 0) {
89 return [
90 ...prev,
91 {
92 senderId: msg.senderId,
93 recieverId: msg.recieverId,
94 message: msg.message,
95 },
96 ];
97 } else {
98 return [msg];
99 }
100 });
101 });
102 socket.on("chat", (chat) => {
103 setMessages(chat);
104 });
105
106 let selectedUserStyle = {
107 color: "black",
108 marginTop: "10px",
109 backgroundColor: "#e9ecef",
110 };
111 return (
112 <div className="">
113 {!isLogedIn && (
114 <Card style={{ width: "18rem" }} className="mx-auto p-2">
115 <Form onSubmit={submitLogin}>
116 <Card.Title className="text-center">Login</Card.Title>
117 <Form.Control
118 type="text"
119 placeholder="Enter Name"
120 onChange={onChangeHandler}
121 />
122 <Button
123 variant="primary"
124 type="submit"
125 className="mt-2 btn btn-primary btn-sm btn-block"
126 >
127 Login
128 </Button>
129 </Form>
130 </Card>
131 )}
132 {isLogedIn && (
133 <div className="container-fluid mt-2 fixed-top">
134 <div className="row">
135 <div className="col-2 vh-100">
136 <div style={{ overflowY: "scroll", height: "100%" }} className="hide-scrollbar">
137 <p
138 style={{ backgroundColor: "#198754" }}
139 className=" rounded-top p-2"
140 >
141 Users
142 </p>
143 <ul style={{ listStyleType: "none", paddingLeft: "0px" }} >
144 {users &&
145 users.map((item) => {
146 if (logedInUser && logedInUser.id != item.user.id) {
147 return (
148 <li
149 role="button"
150 className="rounded m-1"
151 style={
152 item.user.id == reciever
153 ? selectedUserStyle
154 : { marginTop: "10px" }
155 }
156 key={item.user.id}
157 onClick={() =>
158 getChat(item.user.id, logedInUser.id)
159 }
160 >
161 <img
162 src={item.user.imgPath}
163 alt=""
164 style={{ height: "20%", width: "20%" }}
165 className="rounded-circle rounded-fluid"
166 />{" "}
167 {item.user.name}
168 </li>
169 );
170 }
171 })}
172 </ul>
173 </div>
174 </div>
175 <div className="col-10 ">
176 <div
177 className="vh-100 border-start"
178 style={{ position: "relative" }}
179 >
180 <div
181 className="rounded-top p-2 d-flex justify-content-between align-items-center"
182 style={{ backgroundColor: "#198754" }}
183 >
184 <p className="m-0">Chat</p>
185 <p
186 className="m-0"
187 onClick={() => {
188 userLogout();
189 }}
190 role="button"
191 >
192 Logout
193 </p>
194 </div>
195 <ul
196 className="hide-scrollbar"
197 style={{
198 listStyleType: "none",
199 overflowY: "scroll",
200 height: "100%",
201 }}
202 >
203 {messages &&
204 messages.map((item, index) => {
205 if (item.senderId == logedInUser.id) {
206 return (
207 <li
208 key={index}
209 style={{
210 display: "inline-block",
211 clear: "both",
212 backgroundColor: "blue",
213 padding: "10px",
214 color: "white",
215 borderRadius: "30px 10px 10px 40px",
216 float: "right",
217 marginBottom: "10px",
218 }}
219 >
220 <strong>{item.message}</strong>
221 </li>
222 );
223 } else {
224 return (
225 <li
226 key={index}
227 style={{
228 display: "inline-block",
229 clear: "both",
230 float: "left",
231 backgroundColor: "#f1f1f1",
232 padding: "10px",
233 color: "black",
234 borderRadius: "10px 30px 40px 10px",
235 marginBottom: "10px",
236 }}
237 >
238 <strong>{item.message}</strong>
239 </li>
240 );
241 }
242 })}
243 </ul>
244 <div
245 style={{
246 position: "absolute",
247 bottom: 0,
248 width: "100%",
249 boxSizing: "border-box",
250 }}
251 >
252 <div className="pb-2 d-flex">
253 <input
254 type="text"
255 style={{ width: "100%", padding: "10px" }}
256 value={input}
257 onChange={(e) => {
258 setInput(e.target.value);
259 }}
260 />
261 <button
262 style={{ width: "100px", padding: "10px" }}
263 onClick={() => {
264 sendMessage();
265 }}
266 >
267 send
268 </button>
269 </div>
270 </div>
271 </div>
272 </div>
273 </div>
274 </div>
275 )}
276 </div>
277 );
278}
279
280export default App;
About
Moiz is a software engineer from Arid University with a passion for writing tech tutorials and doing coding. I am continously produce JavaScript and other web development technology tutorials in concepts through easy-to-understand explanations written in plain English.I have expertise in next js ,react js ,javascript,html,bootstrap and node js.
Follow him on TwitterHassan is a software engineer from kohat university of science and technology with a passion for writing tech tutorials and doing javascript practices on daily basis.I have expertise in next js ,react js ,javascript,html,bootstrap and node js. Problem Solving and making concpets is my strong point.
Follow him on TwitterTags
Click to see all tutorials tagged with: