A full-stack realtime chat app built with React, Node.js, Express, MongoDB, and Socket.IO. The app features real-time private messaging, online user tracking, JWT authentication, and notifications, using custom APIs, context API, and custom hooks for global state management.
- Authentication: Secure login and registration via JWT
- Realtime Messaging: Bi-directional communication with Socket.IO
- State Management: Using Context API and custom hooks
- RESTful APIs: Powered by Express.js
- Notifications: Instant in-app alerts for new messages
- Custom Hooks: For API calls, state updates, and effects
- Online Users: Real-time online/offline status
Demo Video: Watch
Postman Collection: Download here
- React (Vite)
- React Router DOM
- Context API & Hooks
- Bootstrap + Google Fonts
- Socket.IO Client
- Node.js + Express.js
- MongoDB + Mongoose
- JWT Authentication
- Socket.IO Server
npm install express mongoose dotenv cors jsonwebtoken bcrypt socket.io
/models
/routes
/controllers
-
Hash passwords in User model
-
Endpoints:
POST /register
POST /login
GET /users/:id
GET /users
-
Secure routes with JWT
Fig1: Authentication
-
Chat schema includes
members: [userId]
-
Endpoints:
POST /chats
GET /chats/:userId
GET /chats
Fig2: User Chats
-
Message schema includes
chatId
,senderId
,text
,timestamp
-
Endpoints:
POST /messages
GET /messages/:chatId
Fig3: Send Messages
npm create vite@latest my-chat-app
Login
,Register
,Home
,Chat
Navbar
,ChatSidebar
,ChatBox
,UserList
Fig4: ChatBox
- Bootstrap + custom Google Font
import { createContext } from "react";
export const AuthContext = createContext();
const [user, setUser] = useState(null);
<AuthContext.Provider value={{ user, setUser }}>
{children}
</AuthContext.Provider>;
const { user } = useContext(AuthContext);
const updateRegisterInfo = useCallback((info) => {
setRegisterInfo(info);
}, []);
const data = await response.json();
if (!response.ok) {
return { error: true, message: data.message || data };
}
return data;
const [registerInfo, setRegisterInfo] = useState({
name: "",
email: "",
password: "",
});
const { registerUser, registerError, isRegisterLoading } =
useContext(AuthContext);
<Form onSubmit={registerUser}>
{registerError?.error && <Alert>{registerError.message}</Alert>}
</Form>;
-
Manage:
- Current chat
- Messages
- Notifications
- Sidebar: Existing chats + users
- Main: Messages + input field
Fig5 : New Users
Fig6: Realtime Messages
- Custom hook for fetching messages
- Scroll to last message using
useRef
const scrollRef = useRef();
useEffect(() => {
scrollRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages]);
REST API | WebSocket |
---|---|
Stateless | Stateful |
Unidirectional | Bidirectional |
Request-Response | Event-driven |
Multiple TCP Connections | Single Persistent TCP |
-
Initialize
socket.io
on Express -
Events:
connection
sendMessage
getMessage
getNotification
Fig7: Socket Connection
const socket = useRef();
useEffect(() => {
socket.current = io("http://localhost:PORT");
socket.current.emit("newUser", user._id);
}, []);
Fig7: Online Users
socket.current.on("getMessage", (message) => {
setMessages((prev) => [...prev, message]);
});
socket.current.on("getNotification", (res) => {
const isChatOpen = currentChat?.members.includes(res.senderId);
setNotifications((prev) => [{ ...res, isRead: isChatOpen }, ...prev]);
});
Fig8: Notifications
- Group Chats
- Media Sharing
- Typing Indicators
- Read Receipts