I want to add a small chatting feature in my mern app. I didn"nt want to watch a long course on it so I searched and found a blog on how to make a chat app with mern using socket.io.
MY BACKEND (server.js) file:
require("dotenv").config();
const express = require("express");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const cors = require("cors");
const http = require("http");
const socketio = require("socket.io");
const { addUser, getAllUsers, getUser, removeUser } = require("./utils");
const app = express();
const port = process.env.PORT || 5000;
const server = http.createServer(app);
app.use(bodyParser.urlencoded({ extended: true }));
mongoose
.connect(process.env.DATABASE_CONNECTION_STRING, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log("Connected to database");
})
.catch((error) => {
console.log(error);
});
app.use(express.json());
app.use(cors());
app.options("*", cors());
const io = socketio(server, { wsEngine: "ws" });
io.on("connection", (socket) => {
socket.on("join", (data) => {
const { name, room } = data;
const { user, error } = addUser({ id: socket.id, name, room });
if (error) return;
});
socket.emit("message", {
user: "admin",
text: `${user.name}, it's great to see you in here.`,
});
socket.broadcast.to(user.room).emit("message", {
user: "admin",
text: `${user.name} has just landed to the room.`,
});
socket.join(user.room);
io.to(user.room).emit("room-data", {
room: user.room,
users: getAllUsers(user.room),
});
socket.on("left", () => {
const user = removeUser(socket.id);
user &&
io.to(user.room).emit("message", {
user: "admin",
text: `${user.name} has just left `,
});
});
socket.on("send-message", (message) => {
const user = getUser(socket.id);
io.to(user.room).emit("message", {
user: user.name,
text: message,
});
io.to(user.room).emit("room-data", {
room: user.room,
users: getAllUsers(user.room),
});
});
});
app.listen(port, () => {
console.log(`Server listening on port ${port}`);
});
MY BACKEND (utills.js) folder:
let users = [];
const addUser = ({ id, name, room }) => {
name = name.trim().toLowerCase();
room = room.trim().toLowerCase();
const userExists = users.find(
(user) => user.name === name && user.room === room
);
if (!user || !room || userExists) return { error: "error" };
const user = { id, name, room };
users = [...users, user];
return { user };
};
const removeUser = (id) => {
const i = users.findIndex((user) => user.id === id);
return i !== -1 ? users.splice(i, 1)[0] : null;
};
const getUser = (id) => users.filter((user) => user.id === id)[0];
const getAllUsers = (room) => users.filter((user) => user.room === room);
module.exports = { addUser, removeUser, getAllUsers, getUser };
MY FRONTEND my main(Chat.js) file:
import React, { useEffect, useState } from "react";
import { Box } from "@chakra-ui/react";
import io from "socket.io-client";
import { useSelector } from "react-redux";
import { useLocation } from "react-router-dom";
import { userChats } from "../../../../redux/ChatRequests";
import Info from "./Info";
import ChatVeiw from "./ChatVeiw";
const Chat = (name, room) => {
let socket;
const location = useLocation();
const [users, setUsers] = useState([]);
const [messages, setMessages] = useState([]);
const auth = useSelector((state) => state.auth);
const [chat, setChat] = useState([]);
useEffect(() => {
socket = io("http://localhost:5000/");
socket.emit("join", { name, room });
return () => {
socket.emit("left");
socket.off();
};
}, ["http://localhost:5000/", location.search]);
useEffect(() => {
socket.on("message", (message) => setMessages([...messages, message]));
socket.on("room-data", ({ users }) => setUsers(users));
});
useEffect(() => {
const getChats = async () => {
try {
const { data } = await userChats(auth._id);
setChat(data);
console.log(data);
} catch (error) {
console.log(error);
}
};
getChats();
}, [auth]);
return (
<Box pt={{ base: "130px", md: "80px", xl: "80px" }}>
<main>
<Info room={room} users={users} />
<ChatVeiw messages={messages} name={name} room={room} />
</main>
</Box>
);
};
export default Chat;
MY FRONTEND (ChatRequests.js) file:
import axios from "axios";
const API = axios.create({ baseURL: "http:localhost:5000" });
export const userChats = (id) => API.get(`/chat/${id}`);
MY FRONTEND (ChatVeiw.js) file:
import React from "react";
import ScrollToBottom from "react-scroll-to-bottom";
import { useForm } from "react-hook-form";
const ChatVeiw = ({ messages, name, room }) => {
let socket;
const { register, handleSubmit, reset } = useForm();
const sendMessages = ({ message }) => {
message && socket.emit("send-message", message);
reset();
};
return (
<section>
<ScrollToBottom>
{messages.map((message) => (
<li>
<span>{message.user}</span>
<p>{message.text}</p>
</li>
))}
</ScrollToBottom>
<form onSubmit={handleSubmit(sendMessages)}>
<input type="text" {...register("message", { required: true })} />
<button type="submit">Send</button>
</form>
</section>
);
};
export default ChatVeiw;
MY FRONTEND my(Info.js):
const Info = ({ room, users }) => {
return (
<section>
<header>
<h2>{room}</h2>
</header>
<ul>
{users.map((user) => (
<li>{user}</li>
))}
</ul>
</section>
);
};
export default Info;
The is also a form to enter your chat room:
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";
const Form = () => {
const { register, handleSubmit } = useForm();
const navigate = useNavigate();
const onSubmit = ({ name, room }) => {
navigate(`/chat?name=${name}&room=${room}`);
};
return (
<main className="form">
<form onSubmit={handleSubmit(onSubmit)}>
<input type="text" {...register("name", { required: true })} />
<input type="text" {...register("room", { required: true })} />
<button type="submit">Talk</button>
</form>
</main>
);
};
export default Form;
I tried googling the answer and the closest I got was: https://github.com/socketio/socket.io/issues/3859
None of the suggestions worked for me.
I am using react to style my chat and he seem to be using vite.
Here is the 3 part blog I am reading:
PART 1: https://javascript.plainenglish.io/build-your-own-realtime-chat-app-with-mern-stack-c5908ba75126
PART 2: https://javascript.plainenglish.io/build-your-own-realtime-chat-app-with-mern-stack-f203af2e066e
PART 3: https://javascript.plainenglish.io/build-your-own-realtime-chat-app-with-mern-stack-1f2f0c022576
When I try to test my application I get an error of: TypeError: this.opts.wsEngine is not a constructor(In my backend server)
Please help me with problem. Thank you