Hyperapp — это минималистичный фронтенд-фреймворк, который сочетает
виртуальный DOM, управление состоянием и реактивные обновления. Несмотря
на компактность, Hyperapp предоставляет гибкость для интеграции с
внешними API и выполнения HTTP-запросов. Работа с сетью в Hyperapp
обычно строится вокруг действий (actions), которые изменяют
состояние приложения на основе полученных данных.
fetch в действияхДля взаимодействия с RESTful API используется стандартная функция
JavaScript fetch. Основная идея — отправка запроса к
серверу, обработка ответа и обновление состояния через действия.
Пример базового запроса:
import { h, app } from "https://unpkg.com/hyperapp?module";
const state = {
todos: [],
loading: false,
error: null
};
const actions = {
fetchTodos: () => async (state, actions) => {
actions.setLoading(true);
try {
const response = await fetch("https://jsonplaceholder.typicode.com/todos");
if (!response.ok) throw new Error("Ошибка сети");
const data = await response.json();
actions.setTodos(data);
} catch (err) {
actions.setError(err.message);
} finally {
actions.setLoading(false);
}
},
setTodos: (todos) => ({ todos }),
setLoading: (loading) => ({ loading }),
setError: (error) => ({ error })
};
const view = (state, actions) => (
h("div", {}, [
state.loading && h("p", {}, "Загрузка..."),
state.error && h("p", {}, `Ошибка: ${state.error}`),
h("ul", {}, state.todos.map(todo => h("li", {}, todo.title))),
h("button", { onclick: actions.fetchTodos }, "Загрузить список")
])
);
app({ init: state, view, actions, node: document.getElementById("app") });
В этом примере:
try/catch.loading, error,
todos) управляется действиями, что обеспечивает реактивное
обновление интерфейса.Для отправки данных на сервер используется объект конфигурации
fetch, включающий метод, заголовки и тело запроса:
const actions = {
addTodo: (title) => async (state, actions) => {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/todos", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ title, completed: false })
});
if (!response.ok) throw new Error("Не удалось создать задачу");
const newTodo = await response.json();
actions.setTodos([...state.todos, newTodo]);
} catch (err) {
actions.setError(err.message);
}
}
};
Ключевые моменты:
method: "POST" определяет тип запроса.Content-Type важен для JSON.JSON.stringify.В Hyperapp состояние должно оставаться предсказуемым. При работе с сетью рекомендуется:
loading)
и ошибок (error).Пример структуры состояния:
const state = {
data: null,
loading: false,
error: null
};
Асинхронное действие:
const actions = {
fetchData: () => async (state, actions) => {
actions.setLoading(true);
actions.setError(null);
try {
const response = await fetch("/api/data");
const data = await response.json();
actions.setData(data);
} catch (err) {
actions.setError(err.message);
} finally {
actions.setLoading(false);
}
},
setData: (data) => ({ data }),
setLoading: (loading) => ({ loading }),
setError: (error) => ({ error })
};
Такой подход делает интерфейс отзывчивым и устойчивым к сетевым ошибкам.
Часто требуется отправлять запросы с динамическими параметрами:
const actions = {
fetchUser: (userId) => async (state, actions) => {
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId}`);
const user = await response.json();
actions.setUser(user);
} catch (err) {
actions.setError(err.message);
}
},
setUser: (user) => ({ user }),
setError: (error) => ({ error })
};
Hyperapp подходит для интеграции с любыми REST или GraphQL API. Для
REST достаточно использовать fetch с методами
GET, POST, PUT,
DELETE. Для GraphQL обычно отправляется POST-запрос с
JSON-телом:
const actions = {
fetchGraphQL: (query) => async (state, actions) => {
try {
const response = await fetch("/graphql", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ query })
});
const result = await response.json();
actions.setData(result.data);
} catch (err) {
actions.setError(err.message);
}
}
};
/graphql.Для параллельных запросов можно использовать
Promise.all:
const actions = {
fetchAllData: () => async (state, actions) => {
actions.setLoading(true);
try {
const [usersRes, postsRes] = await Promise.all([
fetch("/users"),
fetch("/posts")
]);
const users = await usersRes.json();
const posts = await postsRes.json();
actions.setUsers(users);
actions.setPosts(posts);
} catch (err) {
actions.setError(err.message);
} finally {
actions.setLoading(false);
}
}
};
Такой подход уменьшает время ожидания при множественных зависимых или независимых запросах.
Hyperapp позволяет писать компактный, но мощный код для работы с HTTP-запросами, сохраняя реактивность и управляемость состояния.