image

Building a Real-Time Chat App with Socket.IO, Node.js, and React | Tutorial

6 July 2023 At 5:18 AMLeave A replyPosted by: Ranjit Das

Building a Simple Chat App with Socket.IO and Node.js

In this tutorial, we'll build a basic chat application using Socket.IO and Node.js. Socket.IO is a powerful library that enables real-time, bidirectional communication between web clients and servers. By the end of this tutorial, you'll have a functional chat app where users can join rooms and exchange messages in real-time.

Prerequisites

- Basic understanding of JavaScript and Node.js.
- Node.js and npm installed on your system.

Setting Up the Project

1. Create a new directory for your project and navigate to it in your terminal.

2. Initialize a new Node.js project by running:

1npm init -y

1 Install the required dependencies:
1npm install express socket.io

Creating the Server

  1. Create a file named server.js in your project directory.
  2. Add the following code

1import express from "express";
2import { createServer } from "http";
3import { Server } from "socket.io";
4const PORT =process.env.PORT|| 9000;
5const app = express();
6const httpServer = createServer(app);
7const io = new Server(httpServer, {
8  maxHttpBufferSize:1e8,
9    cors:{
10        origin:"*",
11    }
12});
13
14httpServer.listen(PORT,()=>{
15    console.log(`Server is Running on port : ${PORT}`)
16});
17
18

Congratulation! you have sucessfully created a nodejs server.now follow the next step

3. Initialize or listen the connection for message communication

1io.on("connection", (socket) => {
2 console.log("User is connected : "+socket.id);
3
4}
This will print the socket id to the console whenever a new user is connected to your application.

4. After this we will setup frontend and later we will add the remaining code to the server. You just follow the step.

Creating the Client(Frontend)

We are going to create a react app using Vite.To create react app using vite follow the step

1) Copy and paste the command in terminal

1yarn create vite

Give your project name here. and press enter after this select React and press enter.

Now select Typescrpt or javascript based on your choice in this tutorial i am going to select javascript because many of you didnot know typescript and hit enter

Congrats! You have sucessfully setup your react project.

2. Open your app in vscode and go to src directory and remove all the existing code inside App.jsx file

Install the required dependencies:

1npm install socket.io-client react-scroll-to-bottom

3. Create the main frontent ui.Here you can create your own ui but if you want to use the same ui as i have create just follow and copy the code below.

Create a components follder inside src directory

  • Create a Main.js file inside components folder and paste the code

1import React, { useState } from "react";
2
3const MainTemp = ({
4  onclick,
5  username,
6  onuserchange,
7  room,
8  onroomchange,
9}) => {
10
11
12
13
14  return (
15    <>
16      <div className="container_main">
17        <div className="subcontainer_main">
18            <div className="wrap_main">
19                <div className="heading_main">
20                    <h1>WELCOME TO RANDOM CHAT ROOM</h1>
21                </div>
22                <form onSubmit={onclick} className="content_main_cnt">
23                    <div className="sub_content_main_cnt">
24                    <div className="input_main_cnt">
25                    <input onChange={onuserchange} value={username} type="text" name="username" placeholder="Enter Username" required/>
26                    </div>
27                    <div className="input_main_cnt">
28                        {/* <input onChange={onroomchange} value={room} type="text" placeholder="Group Name" /> */}
29                        <select value={room} onChange={onroomchange} name="roomSelect" className="selectRoom">
30                          <option value="Fun">FUN</option>
31                          <option value="Coding">CODING</option>
32                          <option value="Random">RANDOM</option>
33                        </select>
34                       
35                    </div>
36                    <div className="btn_form_maim">
37                        <button type="submit">JOIN</button>
38                    </div>
39                    </div>
40                   
41                </form>
42            </div>
43
44        </div>
45      </div>
46    </>
47  );
48};
49
50export default MainTemp;
51

Here basically we are creating a form which accepts Your username and that selects the room name from option.

  • onclick->will be fired when the form is submitted.
  • username->Accepts your username
  • onuserchange->Update the username value whenever its changed
  • room->Holds the current room Name
  • onroomchange->Update the room Name whenever its changes

These are the props used here and i have described it properly.

  • Go to App.css and paste the below css code over there

1.App {
2  text-align: center;
3}
4
5.App-logo {
6  height: 40vmin;
7  pointer-events: none;
8}
9
10@media (prefers-reduced-motion: no-preference) {
11  .App-logo {
12    animation: App-logo-spin infinite 20s linear;
13  }
14}
15
16.App-header {
17  background-color: #282c34;
18  min-height: 100vh;
19  display: flex;
20  flex-direction: column;
21  align-items: center;
22  justify-content: center;
23  font-size: calc(10px + 2vmin);
24  color: white;
25}
26
27.App-link {
28  color: #61dafb;
29}
30
31@keyframes App-logo-spin {
32  from {
33    transform: rotate(0deg);
34  }
35  to {
36    transform: rotate(360deg);
37  }
38}
39
40::-webkit-scrollbar {
41  width: 10px;
42}
43
44/* Track */
45::-webkit-scrollbar-track {
46  box-shadow: inset 0 0 5px #0abeef;
47  border-radius: 10px;
48}
49
50/* Handle */
51::-webkit-scrollbar-thumb {
52  background: cyan;
53  border-radius: 10px;
54}
55
56/* Handle on hover */
57::-webkit-scrollbar-thumb:hover {
58  background: transparent;
59}
60
61.container {
62  width: 99%;
63  height: 99vh;
64  background: #282c34;
65  display: flex;
66  justify-content: center;
67  overflow-y: hidden;
68  top: 0;
69  position: absolute;
70  overflow-x: hidden;
71}
72.form_group {
73  background: #282c34;
74  width: 80%;
75  height: 90%;
76  /* background: red; */
77  position: absolute;
78  top: 5%;
79  justify-content: center;
80  display: flex;
81  flex-direction: row;
82  /* background-color: darkcyan; */
83  border-radius: 10px;
84  border: 2px solid cyan;
85  /* box-shadow: 0 0 20px #ececec; */
86  box-shadow: 0 0 20px cyan;
87  flex-wrap: wrap;
88}
89
90.sidebar {
91  content: "";
92  border-radius: 10px;
93  /* background: red; */
94  height: 100%;
95  flex-basis: 35%;
96  width: 100%;
97}
98.main_content {
99  /* background: blue; */
100  border-radius: 10px;
101  flex-basis: 65%;
102  width: 100%;
103  display: flex;
104  /* background: red; */
105  flex-direction: column;
106  position: relative;
107  height: 100%;
108  justify-content: center;
109}
110.main_content_main {
111  /* background: blue; */
112  border-radius: 10px;
113  width: 100%;
114  display: flex;
115  /* background: red; */
116  flex-direction: column;
117  position: relative;
118  height: 100%;
119  justify-content: center;
120}
121.msgtitle {
122  flex-basis: 10%;
123  display: flex;
124  width: 100%;
125  justify-content: center;
126  /* background: red; */
127}
128.fl{
129  width: 100%;
130  height: 100%;
131  display: flex;
132  flex-direction: column;
133 
134}
135.fl span{
136  flex-basis: 10%;
137  color: cyan;
138}
139
140.msgtitle .fl h1 {
141  font-family: poppins;
142  color: cyan;
143  text-shadow: 0 0 20px #61dafb;
144  flex-basis: 90%;
145}
146
147.form_components {
148  width: 100%;
149  display: flex;
150  flex-direction: row;
151  justify-content: flex-end;
152  margin-bottom: 5%;
153  position: relative;
154
155  justify-content: center;
156  /* background: blue; */
157
158  margin-top: 10%;
159}
160
161.main_form {
162  flex-basis: 80%;
163
164  border-radius: 0 0 10px 0;
165  display: block;
166  height: 100%;
167  flex-direction: column;
168}
169.form_element {
170  flex-basis: 100%;
171  display: flex;
172  height: 100%;
173  flex-direction: column;
174
175  /* top: 50%; */
176  justify-content: center;
177  position: relative;
178  width: 100%;
179}
180
181.headin {
182  width: 100%;
183  background: rgb(77, 77, 171);
184  flex: 20%;
185  top: 0;
186
187  display: flex;
188  justify-content: center;
189  border-radius: 0 10px 0 0;
190  z-index: 1000;
191}
192
193.headin_main {
194  /* background: red; */
195  width: 100%;
196  flex-basis: 20%;
197  display: flex;
198  flex-direction: column;
199  justify-content: center;
200}
201.headin_main h1 {
202  color: white;
203  text-shadow: 0 0 30px #282c34;
204  text-align: center;
205
206  /* font-size: 2vw; */
207  /* font-size: 5vmin; */
208}
209.form_components input {
210  width: 70%;
211  padding: 12px 10px;
212  border-radius: 10px;
213  border: 1px solid #282c34;
214  box-shadow: 0 0 20px #626262;
215  margin-right: 10px;
216  margin-left: 1%;
217}
218
219.form_components .btnjoin {
220  padding: 10px 15px;
221  justify-self: center;
222  background: palegoldenrod;
223  border-radius: 10px;
224  font-family: poppins;
225  font-size: 15px;
226  border: 1px solid #282c34;
227  font-weight: 600;
228  cursor: pointer;
229  transition: 0.3s;
230}
231.form_components .btnjoin:hover {
232  background: teal;
233  color: white;
234  border: 1px solid white;
235}
236
237.form_components li {
238  list-style: none;
239  background: #ececec;
240  box-shadow: 0 0 10px darkcyan;
241  padding: 15px 0;
242  border-radius: 10px;
243  width: auto;
244  padding: 10px 10px;
245}
246.scroll {
247  overflow-y: hidden;
248  /* overflow-x: hidden; */
249  display: block;
250
251  /* background: red; */
252  /* margin-top: 50%; */
253  top: 20px;
254}
255.wrap {
256  margin: 20px 0;
257  width: 100%;
258  display: flex;
259  /* background: red; */
260  height: 65%;
261}
262
263.fc {
264  bottom: 0;
265  position: absolute;
266}
267
268.sp {
269  width: 100%;
270  height: 100%;
271  overflow-x: hidden;
272  overflow-y: hidden;
273  /* overflow-y: scroll; */
274}
275
276/* @media only screen and (min-width: 600px) {
277
278  .form_group{
279    width: 80%;
280    top: 10%;
281    
282    
283  }
284  .headin h1{
285    font-size: 35px;
286  }
287} */
288
289/* @media only screen and (min-width: 360px) {
290  .form_group{
291    width: 85%;
292    top: 10%;
293    height: 80%;
294  }
295  .headin h1{
296    font-size: px;
297  }
298
299
300}@media only screen and (min-width: 270px) {
301  .form_group{
302    width: 80%;
303    top: 10%;
304    height: 80%;
305  }
306 
307}
308@media only screen and (min-width: 768px) {
309
310  .form_group{
311    width: 50%;
312    height: 80%;
313  }
314
315} */
316
317.message {
318  /* padding: 2px; */
319  min-width: 150px;
320  /* width: auto; */
321  margin-bottom: 15px;
322  background-color: var(--light-color);
323  border-radius: 5px;
324  justify-self: flex-end;
325  background: lightgrey;
326  font-family: poppins;
327  padding: 1px;
328  /* flex: 1 1 2000px; */
329}
330
331.message .meta {
332  font-size: 15px;
333  font-weight: bold;
334  color: var(--dark-color-b);
335  opacity: 0.7;
336  top: 2px;
337  padding: 0 4px;
338  margin-bottom: 0;
339  margin-left: 2px;
340}
341
342.message .meta span {
343  color: #777;
344  text-align: right;
345  float: right;
346  margin-right: 5px;
347  font-size: 10px;
348}
349#you .message .text {
350  color: #777;
351  text-align: right;
352  float: right;
353  margin-right: 5px;
354  padding: 0 19px;
355  font-size: 16px;
356}
357#others .message .text {
358  color: #777;
359  text-align: left;
360  /* float: right; */
361  margin-right: 5px;
362  padding: 0 19px;
363  font-size: 16px;
364}
365#you .message .meta {
366  text-align: left;
367}
368
369.btnsubmit {
370  padding: 10px 15px;
371  justify-self: center;
372  background: palegoldenrod;
373  border-radius: 10px;
374  font-family: poppins;
375  font-size: 15px;
376  border: 1px solid #282c34;
377  font-weight: 600;
378  cursor: pointer;
379  transition: 0.3s;
380  margin-right: 1%;
381}
382.btnsubmit:hover {
383  background: teal;
384  color: white;
385  border: 1px solid white;
386}
387
388/* If the screen size is 601px wide or more, set the font-size of <div> to 80px */
389@media screen and (min-width: 601px) {
390  .headin h1 {
391    font-size: 36px;
392  }
393}
394
395/* If the screen size is 600px wide or less, set the font-size of <div> to 30px */
396
397.main_sidebar {
398  /* background: green; */
399  display: flex;
400  width: 100%;
401  height: 100%;
402  border-radius: 10px;
403  flex-direction: column;
404  /* justify-content: space-between; */
405}
406
407.main_sidebar .group_info {
408  width: 100%;
409  height: 100%;
410  /* background: blue; */
411  border-radius: 10px 0 0 0;
412  flex-basis: 50%;
413}
414.main_sidebar .usersInfo {
415  width: 100%;
416  height: 100%;
417  border-radius: 0 0 0 10px;
418
419  flex-basis: 50%;
420  /* display: hidden; */
421}
422
423.group_info hr {
424  width: 90%;
425  background-color: #ccc;
426  margin-top: 5%;
427}
428/* .main_content{
429  height: 100%;
430  
431} */
432
433.grpmain {
434  width: 100%;
435  display: flex;
436  flex-direction: column;
437}
438
439.grpmain .grphead {
440  width: 100%;
441  display: flex;
442  justify-content: center;
443}
444
445.grpmain h1 {
446  font-family: poppins;
447  text-shadow: 0 0 20px #61dafb;
448  color: cyan;
449}
450.grpcnt {
451  display: flex;
452  width: 100%;
453  flex-direction: column;
454  justify-content: center;
455}
456.grpcnt p {
457  text-align: center;
458  color: aqua;
459  font-family: poppins;
460  font-weight: 700;
461  text-shadow: 0 0 10px #61dafb;
462  font-style: italic;
463}
464.grpcnt h2 {
465  text-align: center;
466  color: aqua;
467
468  font-family: poppins;
469  font-style: italic;
470}
471
472.usrmain {
473  width: 100%;
474  display: flex;
475  flex-direction: column;
476  height: 100%;
477}
478
479.usrmain .usrhead {
480  display: flex;
481  flex-basis: 10%;
482  width: 100%;
483  /* background: blue; */
484  height: 100%;
485  margin-left: 15px;
486}
487.usrmain .usrhead h4 {
488  color: #61dafb;
489  text-shadow: 0 0 10px #61dafb;
490}
491.usrmain .usrcnt {
492  height: 100%;
493}
494
495/* Message Body Parts */
496
497.main_message {
498  content: "";
499  height: 100%;
500  /* background: red; */
501  flex-basis: 90%;
502  width: 100%;
503}
504
505.message_in {
506  display: flex;
507  width: 100%;
508  flex-direction: column;
509  position: relative;
510
511  height: 100%;
512}
513
514.message_in .show_messages {
515  content: "";
516  flex-basis: 85%;
517}
518
519.message_in .btn {
520  flex-basis: 13%;
521  height: 100%;
522  width: 100%;
523  /* position: relative; */
524}
525
526.btn .msg_div {
527  width: 100%;
528  display: block;
529  height: 100%;
530
531  /* position: relative; */
532}
533.btn .msg_div .msgcntdiv {
534  width: 100%;
535  display: flex;
536
537  border-radius: 0 0 10px 0;
538  height: 100%;
539  flex-wrap: wrap;
540  border: 1px solid #0abeef;
541  border-radius: 10px;
542  box-shadow: 0 0 10px cyan;
543}
544
545.btn .msg_div .msgcntdiv .input {
546  flex-basis: 60%;
547  width: 100%;
548  height: 100%;
549}
550
551.btn .msg_div .msgcntdiv .input textarea {
552  width: 100%;
553  height: 90%;
554  background: transparent;
555  border: none;
556
557  font-size: 19px;
558
559  padding-left: 10px;
560  line-height: 1.5;
561  display: inline-block;
562  resize: none;
563  max-lines: 3;
564  overflow-y: hidden;
565  color: cyan;
566  /* text-decoration: none; */
567  text-decoration: none;
568  font-family: poppins;
569  text-shadow: 0 0 10px #0abeef;
570}
571
572.btn .msg_div .msgcntdiv .input textarea:focus {
573  border: none;
574  outline: none;
575}
576
577.btn .msg_div .msgcntdiv .attachment {
578  flex-basis: 40%;
579  display: flex;
580  flex-direction: row;
581
582  justify-content: center;
583  width: 100%;
584  text-align: center;
585  /* background: #61dafb; */
586  height: 100%;
587  justify-content: space-evenly;
588}
589
590.at1 {
591  width: 50px;
592  fill: hsl(193, 93%, 50%);
593  /* background: red; */
594  display: flex;
595  padding: 5px;
596  cursor: pointer;
597  justify-content: center;
598  flex-direction: column;
599}
600.at1 button {
601  width: 100%;
602  background: transparent;
603  border: none;
604  cursor: pointer;
605}.at1 label {
606  width: 100%;
607  background: transparent;
608  border: none;
609  cursor: pointer;
610  transition: 0.2s;
611}
612#imginput{
613  position: absolute;
614  opacity: 0;
615  z-index: -1;
616  width: 100%;
617}
618.show_messages {
619  /* background: red; */
620  width: 100%;
621  height: 100%;
622  display: block;
623  position: relative;
624}
625.show_messages .messagecontainer {
626  content: "";
627  width: 100%;
628  /* background: cyan; */
629  height: 98%;
630  display: flex;
631  flex-direction: column;
632  /* overflow-y: scroll; */
633  position: absolute;
634}
635.msgg {
636  width: 100%;
637  display: flex;
638  flex-direction: row;
639  margin-bottom: 10px;
640  /* justify-content: flex-end; */
641}
642.msgboxmain {
643  width: 250px;
644  /* background: red; */
645  display: flex;
646  flex-direction: column;
647text-overflow: clip;
648  margin-left: 10px;
649  /* margin-top: 10px; */
650  border: 2px solid #0abeef;
651  box-shadow: 0 0 20px #0abeef;
652  border-radius: 10px;
653  overflow-wrap: break-word;
654}
655
656.msgboxhead {
657  width: 100%;
658  display: flex;
659  justify-content: space-between;
660  overflow-wrap: break-word;
661}
662
663.msgboxhead p {
664  color: cyan;
665  text-shadow: 0 0 10px cyan;
666  margin: 0 15px;
667  margin-top: 2px;
668  font-family: poppins;
669  font-weight: 700;
670  
671}
672.msgboxcnt {
673  width: 100%;
674  display: flex;
675  word-wrap    : break-word;
676  overflow-wrap: break-word;
677 overflow: auto;
678 height: 98%;
679 margin-top: 2%;
680}
681.ptime {
682  font-size: 12px;
683}
684.msgboxcnt p {
685  color: cyan;
686  text-shadow: 0 0 10px cyan;
687  padding: 0 5px;
688  text-overflow: clip;
689
690  
691}
692.msgboxcnt div{
693  width: 100%;
694  display: flex;
695  flex-direction: column;
696  /* border-radius: 10px; */
697  
698}
699.msgboxcnt div img{
700  border-radius: 0 0 0 0;
701}
702.msgboxcnt img {
703 width: 100%;
704 height: 100%;
705 border-radius:0 0 10px 10px;
706
707  
708}
709.ld{
710  position: absolute;
711  bottom: 0;
712  z-index: 1000;
713  width: 100%;
714  background: red;
715}
716.usrcnt {
717  content: "";
718
719  flex-basis: 90%;
720  height: 100%;
721  width: 100%;
722
723  position: relative;
724}
725.scrollingdiv {
726  width: 100%;
727  height: 100%;
728  position: relative;
729  overflow-y: scroll;
730  display: flex;
731  flex-direction: column;
732  position: absolute;
733}
734.cntusrmain {
735  width: 98%;
736  display: flex;
737  border: 1px solid #0abeef;
738  justify-content: space-between;
739  margin-left: 1%;
740  margin-bottom: 10px;
741  box-shadow: 0 0 5px #0abeef;
742}
743.cntusrmain .users {
744  font-family: poppins;
745  padding-left: 15px;
746  color: cyan;
747  text-shadow: 0 0 10px #0abeef;
748  font-size: 10px;
749}
750.cntusrmain .logoonline {
751  font-family: poppins;
752  padding-right: 25px;
753  color: cyan;
754  text-shadow: 0 0 10px #0abeef;
755  font-size: 10px;
756}
757
758#you {
759  justify-content: flex-end;
760}
761#others {
762  justify-content: flex-start;
763}
764
765#you .cntusrmain {
766  margin-right: 2%;
767}
768#others .cntusrmain {
769  margin-left: 2%;
770}
771
772/* Designing Main Page */
773
774.container_main {
775  background: #282c34;
776  content: "";
777
778  width: 100%;
779  height: 100vh;
780  display: flex;
781  justify-content: center;
782}
783
784.subcontainer_main {
785  width: 90%;
786  height: 80%;
787  content: "";
788  border: 2px solid #0abeef;
789  box-shadow: 0 0 20px cyan;
790  top: 10%;
791  position: absolute;
792}
793.subcontainer_main .wrap_main {
794  width: 100%;
795  height: 100%;
796  display: flex;
797  flex-direction: column;
798}
799
800.subcontainer_main .wrap_main .heading_main {
801  flex-basis: 20%;
802  width: 100%;
803  height: 100%;
804  display: flex;
805  justify-content: center;
806}
807.subcontainer_main .wrap_main .heading_main h1 {
808  text-align: center;
809  color: cyan;
810  text-shadow: 0 0 30px #0abeef;
811  font-family: poppins;
812  font-weight: 900;
813  font-style: italic;
814
815}
816.subcontainer_main .wrap_main .content_main_cnt {
817  flex-basis: 80%;
818
819  display: flex;
820  flex-direction: row;
821  justify-content: center;
822  width: 100%;
823  height: 100%;
824  position: relative;
825}
826.sub_content_main_cnt {
827  width: 90%;
828  /* background: olive; */
829  display: flex;
830  flex-direction: column;
831  /* position: relative; */
832  justify-content: center;
833  height: 100%;
834
835  /* justify-content: center; */
836}
837
838.input_main_cnt {
839  margin-bottom: 10%;
840  display: flex;
841  width: 100%;
842
843  justify-content: center;
844}
845
846.input_main_cnt input {
847  padding: 10px 0;
848  width: 90%;
849  border-radius: 10px;
850  background: transparent;
851  border: 1px solid #0abeef;
852  box-shadow: 0 0 10px cyan;
853  color: cyan;
854  text-decoration: none;
855  text-shadow: 0 0 10px cyan;
856  padding-left: 10px;
857  font-family: poppins;
858  font-size: 19px;
859}
860.input_main_cnt input:focus {
861  border: none;
862  outline: none;
863  border: 2px solid cyan;
864}
865.input_main_cnt input:hover {
866  box-shadow: 0 0 50px cyan;
867}
868.btn_form_maim {
869  justify-content: center;
870  display: flex;
871  width: 100%;
872}
873.btn_form_maim button {
874  width: 150px;
875  padding: 10px 0;
876  background: transparent;
877  border: 1px solid cyan;
878  color: cyan;
879  font-family: poppins;
880  font-size: 17px;
881  border-radius: 5px;
882  cursor: pointer;
883  letter-spacing: 0.4em;
884  font-weight: 900;
885
886}
887.btn_form_maim button:hover {
888  /* background: #777; */
889  transition: 0.3s;
890  box-shadow: 0 0 50px cyan;
891  color: cyan;
892  text-shadow: 0 0 10px cyan;
893}
894
895.selectRoom{
896  
897    padding: 10px 0;
898    width: 90%;
899    border-radius: 10px;
900    background: transparent;
901    border: 1px solid #0abeef;
902    box-shadow: 0 0 10px cyan;
903    color: cyan;
904    text-decoration: none;
905    text-shadow: 0 0 10px cyan;
906    padding-left: 10px;
907    font-family: poppins;
908    font-size: 19px;
909    cursor: pointer;
910  
911}
912.selectRoom option{
913  background:#282c34;
914  color: cyan;
915  outline: none;
916  cursor: pointer;
917  
918
919}.selectRoom:hover{
920  background:#282c34;
921  color: cyan;
922  cursor: pointer;
923  box-shadow: 0 0 50px cyan;
924  
925}
926.grpcnt h2 p a {
927  text-decoration: none;
928  color: darkblue;
929  cursor: pointer;
930}
931
932/* 
933.spanuser{
934  width: 100%;
935  display: flex;
936  flex-direction: row;
937} */
938#your{
939
940
941  
942  /* background: red; */
943  justify-content: flex-end;
944}
945#othe{
946  
947  /* background: blue; */
948  justify-content: flex-start;
949}
950.spanuser{
951  width: 100%;
952  display: flex;
953  justify-content: center;
954  flex-direction: column;
955}
956
957.main_cnt_preview{
958  width: 100%;
959  height: 100%;
960  /* background: red; */
961  position: fixed;
962  top: 0;
963  left: 0;
964  /* opacity:0; */
965  /* display: flex; */
966  justify-content: center;
967  flex-direction: row;
968  transition: display 1s linear;
969
970  /* transition: 0.6s; */
971  display: none;
972
973}
974
975.prev{
976  display: block;
977  /* opacity: 1; */
978  
979}
980
981.sub_cnt_preview{
982  width: 79%;
983  height: 89%;
984  background: #777;
985  border-radius: 10px;
986  box-shadow: 0 0 20px #0abeef;
987  margin-top: 2.5%;
988  position: relative;
989  left: 10%;
990}
991.image_preview{
992  width: 100%;
993  height: 100%;
994  border-radius: 10px;
995}
996.image_preview img{
997  width: 100%;
998  height: 100%;
999  object-fit: contain;
1000  border-radius: 10px;
1001}
1002.cancelBtn{
1003  position: absolute;
1004  width: 100%;
1005  /* background: red; */
1006  display: flex;
1007  margin-top: 2%;
1008  justify-content: flex-end;
1009}
1010.cancelBtn button{
1011  margin-right: 2%;
1012  width: 50px;
1013  background: transparent;
1014  border: 2px solid cyan;
1015  box-shadow: 0 0 20px #0abeef;
1016}
1017
1018.cancelBtn button img{
1019  width: 100%;
1020}
1021@media screen and (max-width: 1920px) {
1022  .input_main_cnt input {
1023    width: 60%;
1024  }.selectRoom {
1025    width: 62%;
1026  }
1027  .subcontainer_main {
1028    width: 70%;
1029  }
1030  .input_main_cnt {
1031    margin-bottom: 8%;
1032  }
1033  .fl span{
1034    display: none;
1035  }
1036}
1037
1038@media screen and (max-width: 700px) {
1039  .headin h1 {
1040    font-size: 35px;
1041  }
1042  .sidebar {
1043    display: hidden;
1044    flex-basis: 100%;
1045    height: 50%;
1046  }
1047  .main_content {
1048    flex-basis: 100%;
1049    height: 100%;
1050  }
1051  .form_group {
1052    width: 95%;
1053  }
1054  .sidebar {
1055    display: none;
1056  }
1057  .msgtitle {
1058    font-size: 10px;
1059    text-align: center;
1060  }
1061  .msgboxmain {
1062    width: 200px;
1063  }
1064  .input_main_cnt input {
1065    width: 60%;
1066  }
1067  .selectRoom {
1068    width: 63%;
1069  }
1070  .subcontainer_main {
1071    width: 93%;
1072  }
1073  .input_main_cnt {
1074    margin-bottom: 10%;
1075  }
1076  .subcontainer_main .wrap_main .heading_main h1 {
1077    font-size: 25px;
1078  }
1079  .subcontainer_main {
1080    height: 95%;
1081    top: 0;
1082  }
1083  .fl span{
1084    display: block;
1085  }
1086
1087  .sub_cnt_preview{
1088    width: 94%;
1089    left: 2.5%;
1090    height: 89%;
1091    top: 3.2%;
1092  }
1093
1094}
1095@media screen and (max-width: 350px) {
1096  .headin h1 {
1097    font-size: 30px;
1098  }
1099  .sidebar {
1100    display: hidden;
1101    flex-basis: 100%;
1102    height: 40%;
1103  }
1104  .main_content {
1105    flex-basis: 100%;
1106    height: 60%;
1107
1108    top: 0;
1109  }
1110  .btn .msg_div .msgcntdiv .input {
1111    flex-basis: 50%;
1112  }
1113  .btn .msg_div .msgcntdiv .attachment {
1114    flex-basis: 60%;
1115  }
1116  .fl span{
1117    display: block;
1118  }
1119
1120}
  • Go to Index.css and paste this code

1body {
2  margin: 0;
3  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5    sans-serif;
6  -webkit-font-smoothing: antialiased;
7  -moz-osx-font-smoothing: grayscale;
8}
9
10code {
11  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12    monospace;
13}
14

Initialize Your Socket.io client in App.js File

1import "./App.css";
2import React, { useEffect, useState } from "react";
3const { io } = require("socket.io-client");
4
5const socket = io("http://localhost:8000");
6function App() {
7
8  return (
9    <>
10      
11    </>
12  );
13}
14
15export default App;
16

Now Go to App.js and Import Your Main.js components over there which you have created beore.

1import "./App.css";
2import React, { useEffect, useState } from "react";
3import Main from "./assets/Components/Main";
4
5const { io } = require("socket.io-client");
6
7const socket = io("http://localhost:8000");
8function App() {
9
10
11  const [username,setUsername] = useState("");
12  const [room,setRoomname] = useState("");
13
14  
15  const onclick = (e) => {
16   
17  };
18
19
20  
21
22  return (
23    <>
24      <div className="conatiner">
25    
26          <Main
27            onclick={onclick}
28            value={username}
29            username={username}
30            onroomchange={(e) => {
31              setRoomname(e.target.value);
32            }}
33            onuserchange={(e) => {
34              setUsername(e.target.value);
35            }}
36            room={room}
37          />
38        
39      
40      </div>
41    </>
42  );
43}
44
45export default App;
46

Here Main components is imported and we have passed the props value like username room name and onchange function. After this just run your project using the below command.

1npm run dev

Now your Main Page will look like this

  • Write onclick function copy and paste the below function

Now we are going to work with both server and client whenever a user join the chat we are going to emit the join_room using socket.io and emitting the oin_room join_room from client side and getting that response in server side

1  const [isMainPage,setIsMainPage] = useState(true);
2
3  
4  const onclick = (e) => {
5    const onclick = (e) => {
6      e.preventDefault();
7      // console.log(username);
8      setIsMainPage(false);
9      const data = {
10        username: username,
11        room: room,
12        id: socket.id,
13        time:
14          new Date(Date.now()).getHours() +
15          ":" +
16          new Date(Date.now()).getMinutes(),
17        userType: "new_user",
18      };
19      socket.emit("join_room", data);
20    };
21  
22  };

Here isMainPage basically tells that we are in mainpage and whenever a user join the chat or click on join chat it will become false and chatPage will be displayed

  • We are creating a data object and for storing username,room,socketId,time at which user joins,Usertype
  • and we are emit a function join_room with the data

Lets handle that in server side.

Go to Server.js file and copy and paste the following code

1
2//here we are storing all the users 
3const users = [];
4
5// Join user to chat
6function userJoin(id, username, room) {
7  const user = { id, username, room };
8
9  users.push(user);
10
11  return user;
12}
13
14
15
16// Get room users bascially we are filtering the user using roomname
17function getRoomUsers(room) {
18  return users.filter(user => user.room === room);
19}
20
21
22Listening the Events from client side
23socket.on("join_room",({username,room,time,userType})=>{
24  //getting the username,room,time and user type from client
25
26  //Pusing the user to the user array to join the room
27   const user = userJoin(socket.id,username,room);
28   socket.join(user.room);
29
30  //getting the roomUser from a particular room
31   const data = getRoomUsers(room);
32
33  //After getting the toom Users we are emiting to client side 
34   io.to(user.room).emit("roomUsers",{
35    room:user.room,
36    users:getRoomUsers(user.room)
37   })
38  
39
40  //we are emitting the userdata to room
41   const data ={
42    username:username,
43    room:room,
44    id:socket.id,
45    message:`${username} has joined the chat`,
46    time:time,
47    st:st
48   }
49
50   io.to(room).emit("new_user",data)
51
52
53
54})
55

Here we have handled the event in server side now after getting the request from client we are again sending back the response to to the client

Two event we have to listen on client side

  1. roomUsers -> Send the all room user to the room
  2. new_user -> Send the new user Info to the room

Lets hanlde these two event in client side

Create a Chat.js file in components folder and paste the below code

1import React, { useEffect, useState } from "react";
2import ScrollToBottom from "react-scroll-to-bottom";
3const Chat = ({
4
5  usesrList,
6  sendMessage,
7  onChange,
8  message,
9  roomUsers,
10  id,
11}) => {
12 
13
14 
15
16  return (
17    <>
18      <div className="container">
19        <div className="form_group">
20          <div className="sidebar">
21            <div className="main_sidebar">
22              <div className="group_info">
23                <div className="grpmain">
24                  <div className="grphead">
25                    <h1>Group: {roomUsers.room}</h1>
26                  </div>
27                  <div className="grpcnt">
28                    <div>
29                      <p>😈Nothing will be Stored!!!😈</p>
30                    </div>
31
32                    <p>Acitve : 0</p>
33                    
34                  </div>
35                </div>
36                <hr color="#0abeef" />
37              </div>
38
39              <div className="usersInfo">
40                <div className="usrmain">
41                  <div className="usrhead">
42                    <h4>Currently Online</h4>
43                  </div>
44                  
45                
46                </div>
47              </div>
48            </div>
49          </div>
50
51          <div className="main_content">
52            <div className="msgtitle">
53              <div className="fl">
54                <h1>WELCOME TO RANDOM CHAT ROOM</h1>
55                <div className="spanuser">
56                  <span>Group : {roomUsers && roomUsers.room} </span>
57                </div>
58              </div>
59            </div>
60            <div className="main_message">
61              <div className="message_in">
62                <div className="show_messages">
63                  <div className="messagecontainer">
64                    <ScrollToBottom className="sp">
65                      {usesrList &&
66                        usesrList.map((user) => {
67                          return (
68                            <div
69                              className="msgg "
70                              id={id === user.id ? "your" : "othe"}
71                            >
72                              <div className="msgboxmain">
73                                <div className="msgboxhead">
74                                  <p>{user.username}</p>
75                                  <p className="ptime">{user.time}</p>
76                                </div>
77                                <div className="msgboxcnt">
78                                  { user.message &&  (
79                                    <p>
80                                      {id === user.id && user.userType === "new_user"
81                                        ? "You have Joined The Chat"
82                                        : user.message}
83                                    </p>
84                                  )
85                                    }
86                                </div>
87                              </div>
88                             
89                            </div>
90                          );
91                        })}
92                    </ScrollToBottom>
93                  </div>
94                </div>
95                <div className="btn">
96                  <div className="msg_div">
97                    <form
98                      onSubmit={sendMessage}
99                      id="form"
100                      className="msgcntdiv"
101                    >
102                      <div className="input">
103                        <textarea
104                          className="sb"
105                          spellcheck="false"
106                          type="text"
107                          message={message}
108                          onChange={onChange}
109                        />
110                      </div>
111                    </form>
112                  </div>
113                </div>
114              </div>
115            </div>
116          </div>
117        </div>
118      </div>
119    </>
120  );
121};
122
123export default Chat;
124

  • Add Chat Componnets to Main.js file

1import "./App.css";
2import React, { useEffect, useState } from "react";
3import Main from "./assets/Components/Main";
4import Chat from "./assets/Components/Chat";
5
6const { io } = require("socket.io-client");
7
8const socket = io("http://localhost:8000");
9function App() {
10
11
12  const [username,setUsername] = useState("");
13  const [room,setRoomname] = useState("");
14
15  //checking if we are in MainPage or in chat Page
16  const [isMainPage,setIsMainPage] = useState(true);
17
18
19//storing the message
20  const [message,setMessage] = useState("");
21
22  // when Form is submited this function will be fired while joing the room
23  const onclick = (e) => {
24    const onclick = (e) => {
25      e.preventDefault();
26      // console.log(username);
27      setIsMainPage(false);
28      const data = {
29        username: username,
30        room: room,
31        id: socket.id,
32        time:
33          new Date(Date.now()).getHours() +
34          ":" +
35          new Date(Date.now()).getMinutes(),
36        st: "new_user",
37      };
38      socket.emit("join_room", data);
39    };
40  
41  };
42
43  //store the current Users List
44  const [usesrList, setUserList] = useState([]);
45
46  //Sending the message we will handle it later
47  const sendMessage = async()=>{
48  
49  }
50
51
52  //handle the incoming event from server side and update the Ui
53  useEffect(() => {
54    //getting the roomUsers eveent which we have emited frin server
55    socket.on("roomUsers", ({ users, room }) => {
56      const data = {
57        users: users,
58        room: room,
59      };
60      setRoomUsers(data);
61    });
62
63    //getting the newUsers details
64    socket.on("new_user", (data) => {
65      setUserList((list) => [...list, data]);
66     
67    });
68  }, []);
69
70
71  return (
72    <>
73      <div className="conatiner">
74    
75    {isMainPage?
76          <Main
77            onclick={onclick}
78            value={username}
79            username={username}
80            onroomchange={(e) => {
81              setRoomname(e.target.value);
82            }}
83            onuserchange={(e) => {
84              setUsername(e.target.value);
85            }}
86            room={room}
87          />
88
89          :  <Chat
90         
91          usesrList={usesrList}
92          message={message}
93          onChange={(e) => {
94            setMessage(e.target.value);
95          }}
96          id={socket.id}
97          sendMessage={sendMessage}
98          roomUsers={roomUsers}
99        />}
100        
101      
102      </div>
103    </>
104  );
105}
106
107export default App;
108

Now have successfully created Our Chat Page and handled the joined user

Our Chat Page Will look like thiis

Now handling the message Part

  • Sending the message from client Side

Update the sendMessage Function

1  const sendMessage = async()=>{
2   if( message!=="") {
3      e.preventDefault();
4      const messageData = {
5        room: room,
6        username: username,
7        message: message,
8        id: socket.id,
9        time:
10          new Date(Date.now()).getHours() +
11          ":" +
12          new Date(Date.now()).getMinutes(),
13        st: "message",
14      };
15      await socket.emit("send_message", messageData);
16      // setUserList((list)=>[...list,messageData]);
17
18      setMessage("");
19      e.preventDefault();
20    
21    
22    }
23  }

Lets handle send_message event in server side

Goto server.js and add the following code

1socket.on("send_message",(data)=>{
2  //we are receiving the message and again sending back to the specific room 
3    io.to(data.room).emit("receive_message",data);
4})
5

Now lets handle the received message on Frontend

1useEffect(() => {
2  //basically we are storing all the data in userlist i.e username message socketid and soon(Just adding the message to previous list)
3    socket.on("receive_message", (data, e) => {
4      setUserList((list) => [...list, data]);
5     
6    });
7
8    socket.on("roomUsers", ({ users, room }) => {
9      const data = {
10        users: users,
11        room: room,
12      };
13      setRoomUsers(data);
14    });
15    socket.on("new_user", (data) => {
16      setUserList((list) => [...list, data]);
17      const mes = `${data.message}`;
18      setJoinedMes(mes);
19    
20    });
21  }, []);
22

Congratulation!! You have successfully Created your chat App

For more Info

Github repo: https://github.com/Technicalranjitofficial/Random-chat/tree/main

Building a chat application using Socket.IO, Node.js, and React has provided us with a hands-on experience in harnessing the power of real-time communication.

If you like this blog then share it with your friends.

© Copyright 2023 - Made with 💓 by Ranjit Das All right reserved