Ревью: эффект с подпиской
Вопрос
Перед тобой код на ревью. Скажи вслух, что здесь не так - по убыванию важности.
Читай вслух, как на ревью: сначала что делает код, потом что сломано.
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 ошибок.