I'm in the process of building a real-time chat app using React and socket to get to grips with the basics. Whenever a user sends a message, all other users receive this same message twice.
I'm using react-router to serve a join 'page' and a chat 'page'.
function App() {
return (
<div className="App">
<Router>
<Routes>
<Route path="/" element={<Join />} />
<Route path="/chat/:name" element={<Chat />} />
</Routes>
</Router>
</div>
);
}
In the chat page, which is where the messages are being rendered between users, I'm using the useEffect hook however I am struggling to fully understand it.
function Chat () {
const [messages, addMessage] = useState([{
username: "chatbot",
time: new Date(),
message: "Welcome to the chatroom 😈"
}]);
const location = useLocation();
const [currentUser, updateUser] = useState(() => {
const user = location.pathname.split('/chat/')[1];
socket.emit("join_chat", {
username: user
})
return user;
});
useEffect(() => {
socket.on("receive_message", (data) => {
console.log('received message');
addMessage(prevMessages => {
return [...prevMessages, {
username: data.username,
time: new Date(),
message: data.message
}]
})
})
}, [socket])
const sendMessage = (e) => {
e.preventDefault();
socket.emit("send_message", {
message: currentMessage,
username: currentUser,
});
The console log is run twice on the receiving side every time a message is sent.
From what I understand, the hook allows us to define some code that will be run whenever there is a change to the DOM, so I'm unsure where this change is happening twice?
I'm also unsure as to why the socket.on should live inside useEffect in the first place. If useEffect is only called immediately after a re-render, how is it still receiving every message via the socket?