Hyperapp — минималистичный фронтенд-фреймворк для построения реактивных веб-приложений. Несмотря на свою компактность, Hyperapp легко интегрируется с различными источниками данных, включая REST API, GraphQL и прямые подключения к базам данных через сервер. Работа с базами данных в Hyperapp подразумевает использование действий (actions) и эффектов (effects) для асинхронного взаимодействия с сервером.
Основной поток данных в Hyperapp строится по принципу:
state → view → actions → effects → state
Такой подход позволяет отделить логику получения данных от их отображения, что делает приложение чистым и предсказуемым.
Для работы с базой данных в state обычно создаются отдельные поля, соответствующие типам данных:
const state = {
users: [],
loading: false,
error: null
};
users хранит массив объектов, полученных из базы.loading используется для отображения индикатора
загрузки.error хранит информацию о возможных ошибках при
запросе.Actions отвечают за вызов эффектов и обновление состояния:
const actions = {
fetchUsers: () => (state, actions) => {
return {
loading: true,
error: null,
users: []
};
},
setUsers: (users) => (state) => ({ users, loading: false }),
setError: (error) => (state) => ({ error, loading: false })
};
fetchUsers подготавливает состояние к загрузке.setUsers обновляет данные после успешного запроса.setError фиксирует ошибки.Эффекты выполняются отдельно от действий и могут быть подключены через сторонние API или fetch-запросы:
const effects = {
getUsers: async (props, actions) => {
try {
const response = await fetch('/api/users');
const data = await response.json();
actions.setUsers(data);
} catch (err) {
actions.setError(err.message);
}
}
};
Объединение state, actions и effects:
import { app } FROM "hyperapp";
const state = {
users: [],
loading: false,
error: null
};
const actions = {
fetchUsers: () => (state, actions) => {
actions.getUsers();
return { loading: true, error: null };
},
setUsers: (users) => (state) => ({ users, loading: false }),
setError: (error) => (state) => ({ error, loading: false }),
getUsers: async (props, actions) => {
try {
const response = await fetch('/api/users');
const data = await response.json();
actions.setUsers(data);
} catch (err) {
actions.setError(err.message);
}
}
};
const view = (state, actions) => (
<div>
{state.loading && <p>Загрузка данных...</p>}
{state.error && <p style={{color: "red"}}>{state.error}</p>}
<ul>
{state.users.map(user => <li>{user.name}</li>)}
</ul>
<button oncl ick={actions.fetchUsers}>Загрузить пользователей</button>
</div>
);
app({ init: state, view, actions });
Особенности:
getUsers вызывается через action
fetchUsers.loading помогает управлять индикатором
загрузки.setError.Принцип одинаков: Hyperapp взаимодействует только с конечной точкой (endpoint), а сервер уже занимается непосредственной работой с базой данных.
Для больших наборов данных рекомендуется хранить параметры запроса в state:
const state = {
users: [],
page: 1,
LIMIT: 10,
filter: '',
loading: false,
error: null
};
Actions изменяют фильтры или страницу:
const actions = {
setPage: (page) => (state, actions) => {
actions.fetchUsers({ page });
return { page };
},
setFilter: (filter) => (state, actions) => {
actions.fetchUsers({ filter });
return { filter };
}
};
Эффект getUsers использует эти параметры для
формирования запроса к серверу.
Hyperapp, будучи минималистичным фреймворком, не ограничивает способы
интеграции с базой данных. Структура
state → actions → effects → state позволяет создавать
масштабируемые, асинхронные приложения с чистой архитектурой. Важным
является правильное разделение ответственности: actions изменяют
состояние, эффекты выполняют асинхронные операции, а view отвечает за
визуализацию.