Home > Software engineering >  socket.io client makes several connections instead of just one
socket.io client makes several connections instead of just one

Time:08-01

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.

  • Related