Hyperapp является легковесным JavaScript-фреймворком, который придерживается функциональной архитектуры, основанной на идеях чистых функций, неизменяемого состояния и предсказуемого потока данных. В такой архитектуре ключевым элементом становится понятие эффектов — механизмов, позволяющих взаимодействовать с внешним миром, сохраняя при этом чистоту основной логики приложения.
Эффект в Hyperapp — это объект, который описывает побочное действие, которое должно быть выполнено вне чистой функции обновления состояния (reducer или action). Эффекты отделяют побочные операции от изменения состояния, что позволяет:
Эффект имеет три ключевых компонента:
type) — идентификатор,
определяющий, какой код должен быть выполнен;payload) — параметры,
необходимые для выполнения действия;Простейший пример эффекта в Hyperapp выглядит как объект:
const fetchEffect = {
type: "fetch",
payload: { url: "/api/data" },
callback: (result) => ({ type: "setData", data: result })
};
Эффекты создаются actions и возвращаются вместе с
новым состоянием. В Hyperapp action может возвращать либо новое
состояние напрямую, либо объект { state, effect }, где
effect будет выполнен системой Hyperapp.
Пример асинхронного действия с эффектом:
const actions = {
loadData: () => (state, actions) => ({
...state,
loading: true,
effect: {
type: "fetch",
payload: { url: "/api/data" },
callback: (result) => actions.setData(result)
}
}),
setData: (data) => (state) => ({
...state,
data,
loading: false
})
};
В этом примере loadData не выполняет напрямую
HTTP-запрос, а описывает эффект. Hyperapp затем обрабатывает этот
эффект, вызывая соответствующую функцию (например, пользовательскую
реализацию fetch-эффекта), и после завершения вызывает
callback для обновления состояния.
Hyperapp предоставляет встроенные эффекты для наиболее частых сценариев:
HTTP — выполнение HTTP-запросов;AnimationFrame — синхронизация с циклом рендеринга
браузера;Timeout и Interval — асинхронные операции
с задержкой.Каждый встроенный эффект реализован как функция, принимающая payload и callback, что обеспечивает единообразное поведение и интеграцию с системой state-action.
Пример использования встроенного HTTP-эффекта:
import { app, Http } from "hyperapp";
const actions = {
fetchData: () => (state, actions) => ({
...state,
effect: Http({ url: "/api/data" }, actions.setData)
}),
setData: (data) => (state) => ({ ...state, data })
};
Встроенные эффекты позволяют минимизировать ручное управление асинхронностью и интегрировать побочные действия с функциональной архитектурой Hyperapp.
Создание собственных эффектов расширяет возможности Hyperapp и позволяет обрабатывать любой вид побочных действий: от локального хранилища до WebSocket-соединений.
Пример пользовательского эффекта:
const logEffect = (message) => ({
type: "log",
payload: message,
callback: () => {}
});
const actions = {
logMessage: (message) => () => ({
effect: logEffect(message)
})
};
Для обработки такого эффекта необходимо зарегистрировать его исполнителя при создании приложения:
const effectHandlers = {
log: ({ payload }) => console.log(payload)
};
app({
init: {},
view: () => null,
node: document.getElementById("app"),
actions,
effectHandlers
});
Такое разделение облегчает тестирование: можно подменять эффекты заглушками и проверять логику приложения без взаимодействия с реальными API.
Эффекты являются основным способом работы с асинхронными операциями в Hyperapp. В отличие от традиционных промисов внутри actions, эффекты позволяют:
Пример асинхронного эффекта с обработкой ошибок:
const fetchEffect = ({ url, onSuccess, onError }) => ({
type: "fetch",
payload: url,
callback: (response) => {
if (response.ok) onSuccess(response.data);
else onError(response.error);
}
});
Такой подход полностью сохраняет функциональную чистоту действий и позволяет строить предсказуемый поток данных.
Эффекты становятся мостом между чистым функциональным ядром приложения и внешним миром, позволяя сохранять предсказуемость и контроль над изменениями состояния.
Эта архитектурная концепция является центральной для построения сложных Hyperapp-приложений и лежит в основе функционального управления побочными действиями, обеспечивая высокую модульность и надежность кода.