Frontend (React + TypeScript + Vite)
В этом модуле создадим современный фронтенд на React + TypeScript + Vite для нашего чата.
Перед началом: React, TypeScript. Инструменты: Vite, React 18. Время: ~4 ч.
🔥 Инцидент. Команда пишет фронтенд на Create React App. Сборка — 40 секунд. HMR — 3 секунды. Размер бандла — 2 МБ. CRA мёртв (React team рекомендует Vite). Переход: быстрее сборка, меньше бандл, лучший DX.
📖 Теория
Фокус: современный стек с быстрым DX. Vite — мгновенный dev-сервер на ESM и сборка на Rollup/esbuild, React 18 + TypeScript strict ловят ошибки на этапе компиляции.
Инициализация проекта
bashnpm create vite@latest chat-frontend -- --template react-ts cd chat-frontend npm install react-router-dom
Хук для WebSocket
Создадим кастомный хук для управления WebSocket соединением:
typescript// hooks/useChatSocket.ts import { useEffect, useState } from 'react'; export const useChatSocket = (url: string) => { const [messages, setMessages] = useState<string[]>([]); const [ws, setWs] = useState<WebSocket | null>(null); useEffect(() => { const socket = new WebSocket(url); setWs(socket); socket.onmessage = (event) => { const data = JSON.parse(event.data); setMessages((prev) => [...prev, data.text]); }; return () => socket.close(); }, [url]); const sendMessage = (msg: string) => { if (ws && ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ action: "sendmessage", text: msg })); } }; return { messages, sendMessage }; };
Компонент чата
typescript// components/Chat.tsx import { useChatSocket } from '../hooks/useChatSocket'; export function Chat() { const { messages, sendMessage } = useChatSocket('wss://api.example.com/ws'); const handleSend = (e: React.FormEvent) => { e.preventDefault(); const input = (e.currentTarget.elements[0] as HTMLInputElement); sendMessage(input.value); input.value = ''; }; return ( <div> <ul> {messages.map((msg, i) => <li key={i}>{msg}</li>)} </ul> <form onSubmit={handleSend}> <input type="text" placeholder="Введите сообщение..." /> <button type="submit">Отправить</button> </form> </div> ); }
Управление состоянием
Для сложных состояний используйте Zustand или Jotai:
bashnpm install zustand
typescript// store/chatStore.ts import create from 'zustand'; interface ChatState { messages: Message[]; addMessage: (msg: Message) => void; } export const useChatStore = create<ChatState>((set) => ({ messages: [], addMessage: (msg) => set((state) => ({ messages: [...state.messages, msg] })), }));
В следующем модуле превратим приложение в PWA.
💱 Компромиссы (Trade-offs)
| Решение | Плюсы | Минусы |
|---|---|---|
| Vite (ESM + Rollup/esbuild) | Мгновенный dev-сервер, быстрая сборка, маленький бандл | Конфиг отличается от webpack, часть плагинов не совместима |
| Create React App | Привычный setup, много туториалов | Мёртв (React team снял поддержку), медленный, тяжёлый бандл |
| React 18 + TypeScript strict | Тип-безопасность, catch ошибок в compile-time | Строжайший онбординг, больше аннотаций |
Кастомный хук useChatSocket | Логика WS инкапсулирована, переиспользуема | Нет reconnect/heartbeat из коробки (см. М3) |
| Zustand для стейта | Минимум boilerplate, без Provider | На масштабе — глобальные сторы (см. М4, М9) |
🧩 Проверь себя
1. React 19 + TypeScript strict — зачем?
2. Кастомный хук useChatSocket управляет...
3. WebSocket reconnect с exponential backoff — зачем?
4. Vite для React+TS — главное преимущество?
5. Vite использует нативный ES modules в dev для...
🔗 Мостик к Модулю 2
Vite настроен. Спроектируем архитектуру приложения.