Может кто-нибудь сказать, пожалуйста, что не так в этом событии сокета? - PullRequest
1 голос
/ 17 апреля 2020

Я отправил два события, когда пользователь присоединился и ушел (user_joined и user_left). Он работает на стороне сервера, но не работает на стороне клиента.

Код на стороне сервера: (работает, показывает console.log при каждом подключении)

io.on('connection', function (socket) {
    const id = socket.id;

    /**
     * User Join Function
     */
    socket.on('join', function ({ name, room }) {
        const { user } = addUser({id, name, room}); // add user to users array
        socket.join(user.room);
        socket.emit('user_joined', users); // emit event with modified users array
        console.log(id, 'joined')
    })

    /**
     * User Disconnect function
     */
    socket.on('disconnect', () => {
        removeUser(id); // remove user form users array
        socket.emit('user_left', users);  // emit event with modified users array
        console.log(id, 'left')
    })


})

Код на стороне клиента: (Не стреляет по user_joined или user_left)

const [players, setPlayers] = useState([]);

const ENDPOINT = 'localhost:5000';
socket = io(ENDPOINT);

useEffect(() => {
    const name = faker.name.firstName() + ' ' + faker.name.lastName();
    socket.emit('join', {name, room: 'global'}); // it's working fine

    return () => {
        socket.emit('disconnect');
        socket.off();
    }

}, [])

useEffect(() => {

    socket.on('user_joined', (users) => {
        setPlayers(users);
    }); // >>> Not Working <<<

    socket.on('user_left', (users) => {
        setPlayers(users);
    }); // >>> Not Working <<<

    console.log(socket) // it's working fine

}, [players]);

1 Ответ

1 голос
/ 17 апреля 2020

Экземпляр socket необходимо создать только один раз. В вашем случае он создается при каждом повторном рендеринге. Также вам не нужно 2 useEffects.

Поместите создание экземпляра socket и объедините ваш 2 useEffects в 1 и предоставьте пустой массив в качестве зависимости. При этом ваш useEffect выполняется только один раз, а не при каждом повторном рендеринге.

Попробуйте это

const [players, setPlayers] = useState([]);

useEffect(() => {
    const ENDPOINT = 'localhost:5000';
    socket = io(ENDPOINT);

    const name = faker.name.firstName() + ' ' + faker.name.lastName();
    socket.emit('join', {name, room: 'global'});

    socket.on('user_joined', (users) => {
        setPlayers(users);
    });

    socket.on('user_left', (users) => {
        setPlayers(users);
    });

    console.log(socket);

    return () => {
        socket.emit('disconnect');
        socket.off();
    }

}, []);
...

Если вы хотите использовать экземпляр сокета в другом места вашего компонента затем использовать useRef. С помощью useRef вы всегда получаете один и тот же экземпляр, если не изменили его.

создайте сокет с refs

...
const [players, setPlayers] = useState([]);
const ENDPOINT = 'localhost:5000';

const socketInstance = useRef(io(ENDPOINT));// in react, with useRef, you always get the same instance unless you mutate it.
useEffect(() => {
    // socketInstance.current = io(ENDPOINT);

    const name = faker.name.firstName() + ' ' + faker.name.lastName();
    socketInstance.current.emit('join', {name, room: 'global'});

    socketInstance.current.on('user_joined', (users) => {
        setPlayers(users);
    });

    socketInstance.current.on('user_left', (users) => {
        setPlayers(users);
    });

    console.log(socketInstance.current);

    return () => {
        socketInstance.current.emit('disconnect');
        socketInstance.current.off();
    }

}, []);
...
...