0Pricing
React Academy · Урок

Создание компонента чата в реальном времени

Отображайте сообщения в реальном времени в прокручиваемом списке чата, используя события WebSocket и состояние React.

«Создание компонента чата в реальном времени» — бесплатный урок React Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Academy содержит 4 уроков всего.

Архитектура компонента чата

Чат в реальном времени состоит из трёх частей: списка сообщений (отображение), поля ввода сообщения (отправка) и уровня соединения WebSocket/Socket.IO. Храните логику сокета в пользовательском хуке.

Структура данных сообщения

Определите интерфейс TypeScript для сообщений чата, чтобы типы компонента оставались безопасными на всём протяжении работы.

interface Message {
  id: string;
  text: string;
  sender: string;
  timestamp: number;
}

const [messages, setMessages] = useState<Message[]>([]);

Хук useChat

Инкапсулируйте соединение, состояние сообщений и функцию отправки в одном хуке.

function useChat(roomId: string) {
  const [messages, setMessages] = useState<Message[]>([]);

  useEffect(() => {
    socket.connect();
    socket.emit('join-room', roomId);
    socket.on('message', (msg: Message) => setMessages(m => [...m, msg]));
    return () => {
      socket.off('message');
      socket.emit('leave-room', roomId);
      socket.disconnect();
    };
  }, [roomId]);

  const sendMessage = useCallback((text: string) => {
    const msg: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
    socket.emit('message', msg);
  }, []);

  return { messages, sendMessage };
}

Компонент списка сообщений

Отображайте сообщения в прокручиваемом списке. Используйте useRef для нижнего элемента-маркера и прокручивайте к нему список при появлении новых сообщений.

function MessageList({ messages }: { messages: Message[] }) {
  const bottomRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    bottomRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  return (
    <div className="message-list">
      {messages.map(msg => (
        <div key={msg.id} className={`msg ${msg.sender === 'me' ? 'mine' : 'theirs'}`}>
          <span>{msg.sender}</span>
          <p>{msg.text}</p>
        </div>
      ))}
      <div ref={bottomRef} />
    </div>
  );
}

Компонент поля ввода сообщения

Управляемое поле ввода, отправляющее сообщение при нажатии клавиши ввода или кнопки. Очищайте поле после отправки.

function MessageInput({ onSend }: { onSend: (text: string) => void }) {
  const [text, setText] = useState('');

  const handleSend = () => {
    if (!text.trim()) return;
    onSend(text.trim());
    setText('');
  };

  return (
    <div className="input-row">
      <input
        value={text}
        onChange={e => setText(e.target.value)}
        onKeyDown={e => e.key === 'Enter' && handleSend()}
        placeholder="Type a message..."
      />
      <button onClick={handleSend}>Send</button>
    </div>
  );
}

Сборка интерфейса чата

Объедините хук и дочерние компоненты в компонент ChatRoom.

function ChatRoom({ roomId }: { roomId: string }) {
  const { messages, sendMessage } = useChat(roomId);

  return (
    <div className="chat-room">
      <h2>Room: {roomId}</h2>
      <MessageList messages={messages} />
      <MessageInput onSend={sendMessage} />
    </div>
  );
}

Оптимистические обновления

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

const sendMessage = useCallback((text: string) => {
  const optimistic: Message = { id: crypto.randomUUID(), text, sender: 'me', timestamp: Date.now() };
  setMessages(m => [...m, optimistic]); // instant feedback
  socket.emit('message', optimistic, (err) => {
    if (err) setMessages(m => m.filter(msg => msg.id !== optimistic.id));
  });
}, []);

Индикаторы набора текста

Отправляйте событие typing при изменении поля ввода (с задержкой) и прослушивайте события набора текста от других пользователей, чтобы отображать индикатор.

const emitTyping = useMemo(() => debounce(() => socket.emit('typing'), 300), []);

useEffect(() => {
  socket.on('user-typing', (user) => setTypingUser(user));
  return () => socket.off('user-typing');
}, []);

Временные метки сообщений

Форматируйте временные метки с помощью Intl.DateTimeFormat, чтобы отображать их с учётом локали.

function formatTime(ts: number) {
  return new Intl.DateTimeFormat('en', { hour: '2-digit', minute: '2-digit' }).format(ts);
}

<span className="timestamp">{formatTime(msg.timestamp)}</span>

Уведомления о прочтении

Отправляйте событие read, когда пользователь просматривает сообщения, и прослушивайте подтверждения прочтения от сервера, чтобы отображать галочки.

Виртуализированный список сообщений

Для длинных историй чата используйте react-window или react-virtual, чтобы виртуализировать список сообщений и отображать только видимые строки.

Ограничение истории сообщений

Ограничивайте массив сообщений в состоянии, чтобы предотвратить неограниченный рост потребления памяти в долгих сеансах.

socket.on('message', (msg: Message) => {
  setMessages(prev => [...prev.slice(-499), msg]); // keep last 500
});

Быстрая проверка

Зачем при появлении новых сообщений в списке чата прокручивать его к нижнему элементу-маркеру?

Итоги

Создайте чат в реальном времени с хуком useChat, инкапсулирующим логику сокета, компонентом MessageList с автоматической прокруткой и компонентом MessageInput, очищающим поле после отправки. Используйте оптимистические обновления для мгновенной обратной связи и ограничивайте историю сообщений, чтобы избежать утечек памяти.

Часто задаваемые вопросы

Урок «Создание компонента чата в реальном времени» бесплатный?

Да — полный текст урока «Создание компонента чата в реальном времени» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Academy, подпишись на CoddyKit PRO. Курс React Academy содержит 4 уроков всего.

Чему я научусь в уроке «Создание компонента чата в реальном времени»?

Отображайте сообщения в реальном времени в прокручиваемом списке чата, используя события WebSocket и состояние React. Ты практикуешь React Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать React Academy?

Предыдущий опыт не требуется. React Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Создание компонента чата в реальном времени»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке React Academy?

Да. Каждый урок React Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы WebSocket в браузере
  2. Использование Socket.IO с React
  3. Создание компонента чата в реальном времени
  4. Переподключение, обработка ошибок и очистка
← Назад к React Academy