Проблема утечки памяти при попытке обновить состояние в useEffect (React Native) - PullRequest
0 голосов
/ 17 января 2020

Я получил компонент, который должен отображать экран чата с сообщением, полученным из socket.io.

Компонент:

    export default function ChatScreen() {

      const [name, setName] = useState("");
      const [message, setMessage] = useState("");

      let socket;

      useEffect(() => {
        socket = io("http://192.168.1.229:3000")
        socket.on("chatMessage", messageObj => {

          console.log(`The message sender is ${messageObj.name}`)

          setName(messageObj.name)
          setMessage(messageObj.message)

        })
      });

      return (
          <Text>
            {name} : {message}
          </Text>
      );
    }

console.log(`The message sender is ${messageObj.name}`)

Работает, но печатает несколько раз. Обновление состояния после не работает вообще. В консоли появляется сообщение:

Предупреждение. Невозможно выполнить обновление состояния React для отключенного компонента. Это неоперация, но она указывает на утечку памяти в вашем приложении. Чтобы исправить, отмените все подписки и асинхронные задачи в% s.% S, функцию очистки useEffect в ChatScreen (в SceneView. js: 9)

Кто-нибудь получит ее?

1 Ответ

1 голос
/ 17 января 2020

Предупреждение ударяет гвоздь по голове. Вы открываете сокет в useEffect(), но не возвращаете из него функцию очистки и не передаете в него массив зависимостей. Первая проблема означает, что если компонент отключен, сокет никогда не будет закрыт. Вторая проблема означает, что каждый раз при рендеринге компонента будет открываться сокет new . Таким образом, каждый раз, когда происходит событие chatMessage, появляется еще один сокет, так что теперь у вас есть два сокета, каждый раз при повторном рендеринге приложения происходит chatMessage и т. Д.

Чтобы решить первую проблему, верните функцию из функции useEffect, которая закрывает сокет. React будет вызывать это, когда компонент размонтируется или когда ловушка срабатывает из-за измененных зависимостей.

Чтобы решить вторую проблему, передайте пустой массив для зависимостей, поскольку вы не используете ничего, переданного через реквизиты в эффект крючка. Пустой массив будет препятствовать запуску ловушки эффектов при каждом повторном рендеринге компонента.

export default function ChatScreen() {
  const [name, setName] = useState("");
  const [message, setMessage] = useState("");

  useEffect(() => {
    const socket = io("http://192.168.1.229:3000");
    socket.on("chatMessage", messageObj => {
      console.log(`The message sender is ${messageObj.name}`);

      setName(messageObj.name);
      setMessage(messageObj.message);
    });

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

  return (
    <Text>
      {name} : {message}
    </Text>
  );
}

Я также рекомендовал бы потратить некоторое время на чтение документации React по ловушке useEffect: Использование ловушки эффектов .

...