Ответ вслух Junior Код-ревью спрашивают часто обновлено

Ревью: эффект с подпиской

Вопрос

Перед тобой код на ревью. Скажи вслух, что здесь не так - по убыванию важности.

Читай вслух, как на ревью: сначала что делает код, потом что сломано.

function Chat({ roomId }) {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const socket = new WebSocket(`wss://api.example.com/room/${roomId}`);
    socket.onmessage = (e) => {
      setMessages([...messages, JSON.parse(e.data)]);
    };
  }, []);

  return <ul>{messages.map((m) => <li>{m.text}</li>)}</ul>;
}

Попробуйте сами

Ответьте вслух за 2 минуты, как на собесе. Потом сверьтесь с тезисами: что прозвучало, а что нет.

Показать ответ и разбор

Коротко

Три ошибки и все серьёзные. Утечка.

Что должно прозвучать в ответе

  • сокет не закрывается - нет функции очистки, утечка на каждом монтировании

  • roomId не в зависимостях - при смене комнаты подписка остаётся на старой

  • setMessages читает messages из замыкания - всегда пустой массив, сообщения затирают друг друга

  • нужна функциональная форма setMessages((prev) => [...prev, msg])

  • у li нет key

  • нет обработки ошибок сокета и разрыва соединения

Что могут спросить следом

  • Как здесь избежать переподключения при каждом рендере?
  • Что будет, если сообщения приходят чаще, чем React успевает рендерить?

Разбор

Три ошибки и все серьёзные.

Утечка. Эффект не возвращает очистку: при каждом монтировании открывается новый сокет, старые остаются. Нужен return () => socket.close().

Устаревшее замыкание. messages захвачен из первого рендера и всегда пустой, поэтому каждое новое сообщение затирает предыдущие - в списке всегда одно. Лечится функциональной формой: setMessages((prev) => [...prev, msg]).

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

Мелочи: нет key у элементов списка, не обработаны onerror и разрыв соединения.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.