@PoisonousHeart

Какие могут не очищаются подписки в useEffect?

Привет. Я столкнулся с проблемой использования хуков и socket.io. У меня нет опыта и горят сроки, поэтому прошу компетентного мнения. Прежде чем описать проблему (я знаю, что проблем там гораздо больше и только буду рад рекомендациям по устранению их, так как я осваиваюсь в MERN), хочу рассказать о ситуации. Итак, на сервере сокет слушает сообщение "connection" там же слушает специальное сообщение от клиента. Если оно приходит - достать из БД список пользователей и отправить клиенту. Что делает клиент, при первом рендере создается 1 функция в хуке callback, то есть она будет создана 1 раз, так как с пустыми депсами. Внутри коннект сокета и установка прилетевших данных с сервака. Теперь проблема: при первом отображении все океy, но при повторном рендере какая-то утечка происходит. Я предполагаю, что это связано с хуком useState, который я использую.

В общем код сервера:
io.sockets.on('connection', socket => {
    console.log('socket connected id: ', socket.id)
    socket.emit('connection', 'hello from server')
    listenReqOnUsers(socket, 'getUserList', 'takeUserList') // Слушает запрос на выборку всех пользователей и отсылает
    listenReqOnMessages(socket, 'giveMessageList', 'getMessageList')
  

    socket.on('disconnect', () => {
        console.log('user disconnected: ', socket.id);
      })
    
})


Код слушателей на сервере:
const listenReqOnUsers = (socket, fromChannel, toChannel) => {
    socket.on(fromChannel, async () => {
        const dataUsers = await User.find()
        socket.emit(toChannel, dataUsers)
    })
}

const listenReqOnMessages = (socket, fromChannel, toChannel) => {
    socket.on(fromChannel, async () => {
        const dataUsers = await Message.find()
        socket.emit(toChannel, dataUsers)
    })
}


И проблемный клиент:

import React, { useCallback, useEffect, useState, useRef} from 'react'
import {Link} from 'react-router-dom'
import DialogUser from './DialogUser'

import socket from '../socket'


const UsersList = () => {
    const [usrs, setUsrs] = useState(null) 
    const usrsRef = useRef()

    const [mes, setMes] = useState(false)

    usrsRef.current = usrs
    
    const getUsrs = useCallback(() => {
        socket.emit('getUserList')
        socket.on('takeUserList', dataUsers => {
            console.log('Подключился к прослушиванию сообщений в user list с id: ', socket.id)
            setUsrs(dataUsers)
        })
    }, [])


    useEffect(() => {
        getUsrs()
    }, [])

    useEffect(() => {
        console.log('обновилось: ', usrsRef.current)
    }, [usrsRef.current])
    

    

    return (
        <div>
            {console.log('users: ', usrsRef.current)}
           <div style={{maxHeight: '150px', height:'150px', overflowY: 'scroll'}}>
               <div>
               {usrsRef.current !== null && usrsRef.current !== undefined && usrsRef.current.map((usr, index) => <div key = {index}>
                   {`usr email: ${usr.email}`}
                   <Link to="#" /*onClick = {() => {setMes(!mes)}}*/ className="btn-floating btn-large waves-effect waves-light red"><i className="material-icons">mail</i></Link>
                   {/* <button onClick = {() => setMes(!mes)}/> */}
               </div>)}
               </div>
            </div>
        {/* {mes && <DialogUser/>} */}
        </div>
    )
}

export default UsersList


Скрин:

6060cbedbe0bb812980200.png
  • Вопрос задан
  • 101 просмотр
Решения вопроса 1
Читайте доку по useEffect
https://reactjs.org/docs/hooks-reference.html#clea...
Вы не освобождаете конекшн при анмаунте
возвращайте из useEffect функцию, которая отключится от сокета
Вот этот кусок кода у вас продолжает выполнятся после того как компонент был отмонтирован,
console.log('Подключился к прослушиванию сообщений в user list с id: ', socket.id)
            setUsrs(dataUsers)

вам 1) вынести его в отдельную функцию, при маунте делать socket.on(' не на анонимную функцию а на именованую
2) При анмаунте делать socket.off если он это поддерживает
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@PoisonousHeart Автор вопроса
Ответ помог, на всякий случай он такой:
useEffect(() => {
        getUsrs()
        return () => {
            socket.offAny('takeUserList')
        }
    }, [])


---------------------------------
В именованую функцию выносить не стал, я не понимаю для чего мне нужен контекст. Или есть еще какая-то разница между ними? Просто я же сохраняю функцию в переменную и в хуке useState, ну понятно, что вызываю её, а также, спасибо Вам большое, удаляю слушателя.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы