So I'm learning the basics of working with Sockets, and I'm trying to establish a connection for Socket.io, one thing I've noticed is that the socket seems to make several attempts before settling the connection. this is what I'm console logging as the client application makes a connection to the server
[0] Client connected: AkHpPfA3ZjXoAPkQAAAB
[0] Client connected: PLRhfqFKVlBnNvq2AAAD
[0] CNFish has joined the chat
[0] Client connected: oX6iyoNsMpf2kLOzAAAF
[0] Client connected: ddV5y6UTczq0DUw4AAAH
This is one refresh of the client-side ReactJS application. where im checking if there is a logged-in user, and if there is I'm making the socket connection and then emitting an event setup
that simply just returns the logged in users username with has joined the chat
but as you can see, it makes several connection attempts after that. I'm pretty new to sockets, but I feel like this shouldn't happen, it should only be one connection right? is this just a drawback to using sockets with react? since react needs to re-render the component for content? or am I setting up the connections wrong?
here is the server side:
const io = new Server(server, { pingTimeout: 5000 });
io.on("connection", (socket) => {
console.log(`Client connected: ${socket.id}`);
socket.on("setup", (userData) => {
console.log(`${userData.username} has joined the chat`.green);
socket.join(userData._id);
socket.emit("connected");
});
});
here is the client, this is my App.js file, again, I'm checking for a logged-in user, and if the user is there, I'm trying to set up a connection to the server.
const { user } = useSelector((state) => state.auth);
const [socket, setSocket] = useState(null);
const [socketConnected, setSocketConnected] = useState(false);
console.log(socketConnected);
if (user) {
setAuthToken(user.token);
}
useEffect(() => {
if (!socket) {
setSocket(io("/"));
}
}, [socket]);
// subscribe to the socket event
useEffect(() => {
if (!socket) return;
socket.emit("setup", user);
socket.on("connected", () => {
setSocketConnected(true);
});
socket.on("disconnect", () => {
setSocketConnected(false);
setSocket(null);
});
// close the socket connection when the component unmounts
return () => {
socket.close();
};
}, [socket]);
CodePudding user response:
So i figured it out, the problem was that as the component refreshes its creating a new socket
connection each time, its important to narrow this down as if you try to emit to that socket, it can create multiple emitting events to that persons socket, for instance if you were sending a message to another person, and that person had connected 3 times, with sockets, when you try to emit to that persons socket (usually each person has one connection) that person would then receive multiple events in the socket.on
handlers.
So the way to handle client side connections via React is to stash the connection in state, im using Redux
therefore im stashing the connection in a piece of state.
here is the code that i created to make sure only 1
socket connection was created.
import io from "socket.io-client";
import { SOCKET_CONNECT, SOCKET_CONNECT_ERROR, SOCKET_CONNECT_SUCCESS } from "../../Constants/socketConstants";
import { errorHandler } from "../../utils/errorHandler";
export const createConnection = () => async (dispatch, getState) => {
try {
// get the user from state
const { user } = getState().auth;
const {
socketConnection: { socket, isConnecting },
} = getState().socket;
if (socket || isConnecting) return;
dispatch({ type: SOCKET_CONNECT });
const connection = io("/");
await connection.on("connect", () => {
dispatch({ type: SOCKET_CONNECT_SUCCESS, payload: connection });
connection.emit("setup", user);
});
} catch (error) {
errorHandler(error, dispatch, SOCKET_CONNECT_ERROR);
}
};
what's happening here is im checking to make sure i havent already started the state, socket
starts out null
and isConnecting
can also be null
but is otherwise a true | false
bool. in this manner, it takes care of any re-render happening inside the application, at dispatch
im setting the isConnecting
to true, and therefore on each render afterwards it simply doesnt get past the if
block, once the connection is made isConnecting
is set to false, and socket
is set to the new connection.
the application now only has 1
open socket connection at all times, instead of multiples.