Вступление
В современной веб-разработке существует множество способов обновления данных в реальном времени. Среди наиболее распространённых методов выделяются Polling и WebSockets. Оба подхода имеют свои уникальные особенности и применения, что делает их подходящими для различных сценариев. В этой статье мы рассмотрим основные различия между Polling и WebSockets, их преимущества и недостатки, а также приведем примеры использования каждого из них в React приложениях на хуках.
Polling
Polling – это метод, при котором клиент периодически отправляет запросы на сервер для получения обновленных данных. Этот подход прост в реализации, но может быть неэффективен при частых запросах, так как он увеличивает нагрузку на сервер и сеть.

Рефетч может происходить при нажатии кнопки, по истечению определенного количества времени, или при любом другом событии.
WebSockets
WebSockets – это протокол, который позволяет устанавливать постоянное соединение между клиентом и сервером. Благодаря этому соединению данные могут передаваться в обоих направлениях в реальном времени, что делает WebSockets более эффективным для приложений, требующих мгновенного обновления данных.

Клиент отправляет запрос, а сервер возвращает ему handshake, после чего устанавливается websocket соединение, в котором данные моментально приходят от клиента до сервера, и наоборот.
Рассмотрим примеры реализации обоих подходов
Создадим 2 приложения: в первом реализуем чат на основе поллинга, добавим пользователю кнопку “обновить”, на которую будет происходить рефетч; во втором же сделаем чат и установим web socket соединение, для моментального обновления данных.
Зависимости
Для реализации задумки мне пригодится всего 2 библиотеки:
shadcn/ui - для красивых ui компонентов
reactuse - лучшая утилитарная библиотека с огромным количеством переиспользуемых react хуков (мы возьмем оттуда useQuery и useWebsocket)
Установим зависимости и нужные нам компоненты из ui библиотеки (это начало будет одинаковым для обоих приложений)
$yarn add @siberiacancode/reactuse
$yarn add tailwindcss
$npx tailwindcss init
$npx shadcn-ui@latest init
$npx shadcn-ui@latest add button card input
Для обоих приложений создадим одинаковый компонент чата. Начнем с обычной верстки. Для этого импортируем из shadcn/ui следующие компоненты: button, input, scroll-area, separator. (см. документацию, чтобы посмотреть как добавлять компоненты)
Создадим развертку компонента Chat:
import { Button } from "./ui/button";
import { Card, CardContent, CardTitle } from "./ui/card";
import { Input } from "./ui/input";
import { ScrollArea } from "./ui/scroll-area";
import { Separator } from "./ui/separator";
const Chat = () => {
return (
<Card className=" w-80 h-96">
<CardTitle>
<div className="p-2">Chat</div>
<Separator />
</CardTitle>
<CardContent className="p-0 flex flex-col">
<ScrollArea className=" w-full h-72">
<div className=" p-2">
<div className="flex">
<div className=" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md">
Message to you
</div>
</div>
<div className="flex justify-end">
<div className=" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md">
Message from you
</div>
</div>
</div>
</ScrollArea>
<div className=" flex ">
<Input placeholder="Your message..." className="" />
<Button className="">Send</Button>
</div>
</CardContent>
</Card>
);
};
export default Chat;
Получим следующий ui:

Добавим type Message:
type Message = {
text: string;
type: "client" | "server";
};
Создадим состояние messages, в котором будем хранить все сообщения:
import { useState } from "react";
const messages = useState<Message[]>([])
Немного поменяем верстку, чтобы в чате отоброжались только сообщения из стэйта messages и на них применялись определенные стили, в соответствии с тем, является ли тип сообщения “server” или “client”
<ScrollArea className=" w-full h-72">
<div className="p-2">
{messages.map((message, index) => {
if (message.type === "client")
return (
<div className="flex justify-end" key={index}>
<div className=" bg-slate-800 text-foreground rounded-md p-1.5 max-w-64 shadow-slate-800 shadow-md">
{message.text}
</div>
</div>
);
else
return (
<div className="flex">
<div className=" bg-slate-300 text-background rounded-md p-1.5 max-w-64 shadow-slate-300 shadow-md">
{message.text}
</div>
</div>
);
})}
</div>
</ScrollArea>;
Добавим хук работы с полями ввода
useField - этот хук из пакета reactuse вы можете использовать для удобного взаимодествия с полями ввода.
const messageInput = useField({initialValue: ''})
Здесь мы задали initialValue, равное пустой строке. Далее мы будем обращаться к messageInput, для взаимодействия с полем ввода.
Добавим к нашему инпуту следующее:
<Input placeholder="Your message..." {...messageInput.register()} />
Таким образом мы регистрируем и привязываем хук к этому полю ввода
1 - Метод Polling
Для каждого из способов нам понадобиться создать свой моковый сервер. В случае с polling воспользуюсь библиотекой от создатиля reactuse -
