Reputation: 409
i have two components: where I set the username and room and then I have the component where is the send message and displays the conversation.
When I login on the component, I navigate to the component and trigger the connection with the socket:
const handleClick = (e) => {
e.preventDefault();
navigate("/chatroom", { state: { username, room } });
};
I have two issues regarding the connection with the socket:
-I´ve tried to start the connection inside an useEffect():
export default function ChatRoom() {
const [chatMessage, setChatMessage] = useState("");
const [showmsg, setShowMsg] = useState([]);
const [showObj, setShowObj] = useState([]);
const [submited, setSubmited] = useState(false);
const handleSubmit = (e) => {
e.preventDefault();
setShowMsg((oldmsg) => [...oldmsg, chatMessage]);
setChatMessage("");
setSubmited(true);
};
const { state } = useLocation(); //to get data from <Home/> component
useEffect(() => {
const socket = io("http://localhost:3000");
//Message from server
socket.on("message", (msg) => {
setShowObj((oldmsg) => [...oldmsg, msg]);
setSubmited(false);
console.log(showObj);
});
//Message to server
socket.emit("chatMessage", {
user: state.username,
text: showmsg[showmsg.length - 1],
}); //pass the last msg
}, [submited]);
ServerSide:
io.on("connection", (socket) => {
//Welcome current user
socket.emit("message", formatMessage("MiouriChat", "Welcome to the chat!"));
//Broadcast when user connects
socket.broadcast.emit(
"message",
formatMessage("MiouriChat", "A user has joined the chat")
);
//Run when clients disconects
socket.on("disconnect", () => {
io.emit("message", formatMessage("MiouriChat", "A user has left the chat"));
});
//Listen to chat message from client
socket.on("chatMessage", (msg) => {
io.emit("message", formatMessage(msg.user, msg.text));
});
});
This way, everytime I submit a msg ([submited] change), the connection is reseted for obvious reason and get the "welcome" messages everytime it reconects.
If I put the connection outside the useEffect(), the connection reseted everytyme I type a letter on the message input (becouse the state updates.)
What is the best solution for this?
Upvotes: 0
Views: 56
Reputation: 10007
For your initial "welcome" message, you want a useEffect
that only runs after the first render of the page as explained in the docs - by specifying an empty dependency array. This is also a really nice place to define the "cleanup" function, where you want to send a "disconnect"
message to your server (in fact the cleanup docs even use a chat API as an example!):
useEffect(() => {
const socket = io("http://localhost:3000");
//Message from server
socket.on("message", (msg) => {
setShowObj((oldmsg) => [...oldmsg, msg]);
console.log(showObj);
});
return () => {
socket.emit("disconnect"); // cleanly disconnect from server
};
}, []); // <- Empty dependency array === only runs after initial render
That solves the "welcome message" and "disconnect" problems, and you no longer need the submited
state variable. I can't really help you with the rest, but again I commend the useEffect
documentation to you, particularly the example which is so applicable to your use case!
Upvotes: 1