Hyperapp — это минималистичный фронтенд-фреймворк для построения реактивных пользовательских интерфейсов. Для создания интерактивных приложений в реальном времени часто требуется интеграция с WebSocket-соединениями. В Hyperapp подход к работе с WebSocket строится на использовании эффектов и событий, что позволяет организовать поток данных между сервером и приложением без нарушения принципов реактивности.
Hyperapp использует эффекты (effects) для побочных
действий, таких как сетевые запросы. Для WebSocket создается отдельный
эффект, который инициализирует соединение и обрабатывает события
onopen, onmessage, onclose и
onerror.
Пример эффекта для WebSocket:
const wsEffect = (url, actions) => (dispatch) => {
const socket = new WebSocket(url);
socket.ono pen = () => {
dispatch(actions.connected());
};
socket.onmess age = (event) => {
const data = JSON.parse(event.data);
dispatch(actions.messageReceived(data));
};
socket.oncl ose = () => {
dispatch(actions.disconnected());
};
socket.oner ror = (error) => {
dispatch(actions.error(error));
};
return () => socket.close();
};
Ключевые моменты:
Состояние приложения содержит поля, отражающие текущее состояние WebSocket:
const state = {
connected: false,
messages: [],
error: null,
};
Действия для управления состоянием:
const actions = {
connected: () => ({ connected: true }),
disconnected: () => ({ connected: false }),
messageReceived: (message) => (state) => ({
messages: [...state.messages, message],
}),
error: (err) => ({ error: err }),
};
Инициализация эффекта при старте приложения:
import { app } from "hyperapp";
app({
init: [state, wsEffect("wss://example.com/socket", actions)],
state,
actions,
view: (state) => (
<div>
<h2>Статус соединения: {state.connected ? "онлайн" : "офлайн"}</h2>
<ul>
{state.messages.map((msg) => <li>{msg.text}</li>)}
</ul>
</div>
),
});
Для отправки сообщений используется отдельное действие, которое взаимодействует с объектом WebSocket. Его удобно хранить в замыкании эффекта:
const wsEffect = (url, actions) => (dispatch) => {
const socket = new WebSocket(url);
socket.ono pen = () => dispatch(actions.connected());
socket.onmess age = (event) => dispatch(actions.messageReceived(JSON.parse(event.data)));
socket.oncl ose = () => dispatch(actions.disconnected());
socket.oner ror = (error) => dispatch(actions.error(error));
const sendMessage = (message) => {
if (socket.readyState === WebSocket.OPEN) {
socket.send(JSON.stringify(message));
}
};
actions.sendMessage = sendMessage;
return () => socket.close();
};
Таким образом, действия Hyperapp остаются чистыми, а логика отправки сообщений инкапсулирована в эффекте.
Для приложений с реальным временем критически важно обрабатывать разрывы соединения. Реализуется это через рекурсивные таймеры и повторные вызовы эффекта:
const reconnectEffect = (url, actions, interval = 5000) => (dispatch) => {
let socket;
const connect = () => {
socket = new WebSocket(url);
socket.ono pen = () => dispatch(actions.connected());
socket.onmess age = (event) => dispatch(actions.messageReceived(JSON.parse(event.data)));
socket.oncl ose = () => setTimeout(connect, interval);
socket.oner ror = (error) => dispatch(actions.error(error));
};
connect();
return () => socket.close();
};
Особенности:
Hyperapp позволяет структурировать события WebSocket так, чтобы каждое сообщение автоматически обновляло состояние:
actions.messageReceived для добавления
сообщений в массив.debounce или throttle.socket.readyState перед отправкой
данных.wss:// для защищенного
соединения.Для сложных приложений с несколькими WebSocket-источниками рекомендуется создавать отдельные эффекты для каждого канала. Каждый эффект инкапсулирует свое соединение и управление событиями, что позволяет:
Эта структура обеспечивает реактивное управление WebSocket-соединениями, позволяет поддерживать чистоту действий и легко масштабируется под сложные сценарии реального времени.