Не работает SocketIO на клиентской части(react)

Пишу Клиент-серверное приложение на express-js, reactjs. Мне нужно добавить real time. Задача сделать timer для всех пользователей одинаковым + liveChat. Решил начать с начального и сразу застрял.

Серверная часть:

const express = require('express');
const PORT = process.env.PORT || 5050;
const userRouter = require('./routes/user.routes');
const gameRouter = require('./routes/game.routes');
const cors = require('cors');
const http = require('http');
const { Server } = require("socket.io");

const app = express();
const server = http.createServer(app);

const io = new Server(server, {
  cors: {
    origin: "http://localhost:3000",
    methods: ["GET", "POST"]
  }
});

io.on('connection', (socket) => {
  console.log('Новое подключение', socket.id);
  
  socket.on('message:created', (message) => {
    console.log('Новое сообщение', message);
  });

});

const corsOptions = {
  origin: '*',
  methods: "*",
  allowedHeaders: "*"
};

app.use(cors(corsOptions));

app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use('/api', userRouter);
app.use('/game', gameRouter);


server.listen(PORT, () => console.log(`Cтарутем на порту ${PORT}`));

часть кода с клиента (react)

import React, { useState, useEffect, useRef } from "react"; 
import './FirstGame.css'
import io from 'socket.io-client';

const socket = io('http://localhost:5050', { transports: ['websocket'] });

const FirstGame = () => {
    const [countdown, setCountdown] = React.useState(11);
    const [currentPage, setCurrentPage] = React.useState(1);
    
    const itemsPerPage = 10;
    
    const startCountdown = () => {
        let timer = 11;
        const timerInterval = setInterval(() => {
          timer--;
          setCountdown(timer);
          if (timer === 0) {
            clearInterval(timerInterval);
          }
        }, 1000);
        return () => {
          clearInterval(timerInterval);
        };
      };
      
      const socketRef = useRef(null);

  useEffect(() => {
    
    socketRef.current = socket;

    socket.on("connect", () => {
      console.log("Соединение установлено", socket.id);
    });

    socket.on("disconnect", () => {
      console.log("Соединение разорвано");
    });

    return () => {
      socket.disconnect();
    };
  }, []);

при запуске сервера, отрабатывают все логи, 1 лог. порт, 2 лог. Новое подключение с socket.id. На клиенте при открытии страницы или перезагрузки срабатывает лог: Соединение разорвано. Хотя на сервере каждый раз отрабатывает новое подключение с новым socket.id.


Ответы (1 шт):

Автор решения: SwaD

Реакт, начиная с 18 версии в строгом режиме <React.StrictMode> в режиме разработки выполняет установку всех компонентов дважды.

В случае с вашим кодом вне компонента происходит инициализация сокета и устанавливается соединение, далее компонент устанавливается(первый раз).

Затем компонент размонтируется и соединение по сокету разрывается и компонент устанавливается повторно(но соединение уже разорвано)

Исправить такое поведение можно, перенеся установку соединения по сокету в useEffect

useEffect(() => {
    const socket = io('http://localhost:5050', { transports: ['websocket'] });
    socketRef.current = socket;

    socket.on("connect", () => {
      console.log("Соединение установлено", socket.id);
    });

    socket.on("disconnect", () => {
      console.log("Соединение разорвано");
    });

    return () => {
      socket.disconnect();
    };
  }, []);

Либо так, сразу при инициализации компонента

const [socket, setSocket] = React.useState(io('http://localhost:5050', { transports: ['websocket'] }));
→ Ссылка