I have a chat window component in my react app. I want to make the component to be able to recieve real-time updates (when a user sends a message, it should auto-render the new message bubble for the recipient). I tried implementing websocket for this but it doesn’t work. The user i send a message to does not recieve it in real time and has to reload the page to get it. can u find whats wrong? Here’s my code:
import { useEffect, useState } from 'react';
import { Button, ChatBubble, Navbar, Textarea } from 'react-daisyui';
import axios from 'axios';
const api = `http://localhost:8000`;
const wsUrl = `ws://localhost:8080`; // WebSocket server URL
function ChatWindow({ recipientNickname, recipientEmail }) {
const client = window.localStorage.getItem('mail');
const [chats, setChats] = useState([]);
const [message, setMessage] = useState('');
const [counter, setCounter] = useState(0);
const [loading, setLoading] = useState(false);
const [ws, setWs] = useState(null); // WebSocket connection
useEffect(() => {
const websocket = new WebSocket(wsUrl);
setWs(websocket);
return () => {
websocket.close();
};
}, []);
useEffect(() => {
if (ws) {
ws.onmessage = (event) => {
const newMessage = JSON.parse(event.data);
setChats((prevChats) => [...prevChats, newMessage]);
};
}
}, [ws]);
async function fetchChats() {
try {
const response = await axios.get(`${api}/users/messages?client=${client}&recipient=${recipientEmail}`);
if (response.data) {
setChats(response.data);
} else {
setChats([]);
}
} catch (e) {
console.log(e);
}
}
useEffect(() => {
fetchChats();
}, [recipientEmail]);
useEffect(() => {
if (counter > 0) {
fetchChats();
}
}, [counter]);
const getCurrentTimestamp = () => {
const currentDate = new Date();
const hours = currentDate.getHours();
const minutes = currentDate.getMinutes();
const day = currentDate.getDate();
const month = currentDate.toLocaleString('default', { month: 'short' });
const year = currentDate.getFullYear();
const formattedTimestamp = `Sent at ${hours}:${minutes} on ${day} ${month} ${year}`;
return formattedTimestamp;
};
const handleSubmit = async (e) => {
e.preventDefault();
if (message) {
const messageData = {
message: message,
client: client,
footer: 'Sending...'
};
setLoading(true);
await axios.post(`${api}/users/messages?client=${client}&recipient=${recipientEmail}&message=${message}×tamp=${getCurrentTimestamp()}`);
ws.send(JSON.stringify(messageData));
setChats([...chats, messageData]);
setMessage('');
setCounter((prevCounter) => prevCounter + 1);
await fetchChats()
setLoading(false);
}
};
return (
<div style={{ marginLeft: 250, marginRight: 20, zIndex: 1 }}>
<div>
<Navbar>
<Navbar.Center style={{ alignItems: 'center' }}>
<Button tag="a" color="ghost" className="normal-case text-xl">
{recipientNickname || 'Chats'}
</Button>
</Navbar.Center>
</Navbar>
</div>
<div className='chats' style={{ maxHeight: '75vh', overflowY: 'auto' }}>
{chats.map((message, index) => (
<ChatBubble key={index} end={message.client === client}>
<ChatBubble.Message>{message.message}</ChatBubble.Message>
{message.client === client ? <ChatBubble.Footer>{message.footer}</ChatBubble.Footer> : <></>}
</ChatBubble>
))}
{loading ? (
<ChatBubble end={true}>
<ChatBubble.Message>{message}</ChatBubble.Message>
<ChatBubble.Footer>Sending...</ChatBubble.Footer>
</ChatBubble>
) : (
<></>
)}
</div>
<div style={{ position: 'absolute', bottom: 10, left: 250, right: 20 }}>
<form onSubmit={handleSubmit}>
<Textarea
rows={1}
style={{ width: '100%', borderRadius: 10, margin: 5 }}
placeholder='Send a message'
className='join-item msg-input'
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSubmit(e);
}
}}
/>
</form>
</div>
</div>
);
}
export default ChatWindow;
Vaidik Rungta is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.