Hyperapp использует минималистичный подход к управлению состоянием и обновлению интерфейса. Одной из ключевых концепций является система Actions, которая позволяет изменять состояние приложения реактивно и декларативно. Actions в Hyperapp представляют собой функции, которые принимают текущее состояние и возвращают новое состояние или функцию для асинхронных операций.
Action — это чистая функция, которая получает два аргумента:
Простейший пример action:
const state = { count: 0 }
const actions = {
increment: (state) => ({ count: state.count + 1 }),
decrement: (state) => ({ count: state.count - 1 })
}
В этом примере increment и decrement
возвращают новое состояние на основе предыдущего. Hyperapp автоматически
объединяет результат с текущим состоянием, создавая новый объект
состояния.
Actions могут принимать аргументы, что позволяет динамически изменять состояние:
const actions = {
add: (amount) => (state) => ({ count: state.count + amount })
}
Вызов actions.add(5) увеличит count на 5.
Такой подход делает код гибким и легко масштабируемым.
Hyperapp поддерживает асинхронные операции через effect
functions. Action может возвращать функцию вместо объекта
состояния. Эта функция получает dispatch и
state, что позволяет выполнять асинхронные вызовы и
вызывать другие actions:
const actions = {
fetchData: () => (state, actions) => {
fetch('/api/data')
.then(res => res.json())
.then(data => actions.setData(data))
},
setData: (data) => ({ data })
}
Такой подход сохраняет реактивность и чистоту архитектуры, отделяя побочные эффекты от чистых изменений состояния.
Hyperapp связывает события с actions напрямую через атрибуты
элементов. События могут быть стандартными DOM-событиями:
onclick, oninput, onsubmit и
другими.
const view = (state, actions) => (
<div>
<button oncl ick={actions.increment}>Увеличить</button>
<button oncl ick={actions.decrement}>Уменьшить</button>
<p>Счётчик: {state.count}</p>
</div>
)
События могут передавать аргументы через стрелочные функции:
<button oncl ick={() => actions.add(10)}>Добавить 10</button>
Actions могут быть сложными и составными. Один action может вызывать другой для создания цепочек логики:
const actions = {
increment: (state) => ({ count: state.count + 1 }),
incrementIfEven: (state, actions) => {
if (state.count % 2 === 0) actions.increment()
}
}
Такая композиция упрощает управление состоянием без необходимости дублировать код.
Для управления формами и input-элементами используется привязка событий к actions:
const state = { text: '' }
const actions = {
updateText: (value) => ({ text: value })
}
const view = (state, actions) => (
<input type="text" value={state.text} onin put={(e) => actions.updateText(e.target.value)} />
)
При каждом изменении текста вызывается updateText,
обновляя состояние и перерисовывая интерфейс.
Для интеграции с внешними системами или выполнения асинхронных операций используют комбинацию actions и effect functions:
const actions = {
logClick: () => (state, actions) => {
console.log('Клик зафиксирован', state)
}
}
<button oncl ick={actions.logClick}>Логировать</button>
Это позволяет централизованно управлять логикой и сохранять реактивность приложения.
Частой задачей является создание динамических списков с действиями добавления, удаления и обновления элементов:
const state = { items: [] }
const actions = {
addItem: (text) => (state) => ({ items: [...state.items, text] }),
removeItem: (index) => (state) => ({
items: state.items.filter((_, i) => i !== index)
})
}
const view = (state, actions) => (
<div>
<input onin put={(e) => actions.addItem(e.target.value)} placeholder="Добавить элемент" />
<ul>
{state.items.map((item, i) => (
<li>
{item} <button oncl ick={() => actions.removeItem(i)}>Удалить</button>
</li>
))}
</ul>
</div>
)
Этот пример демонстрирует, как Actions позволяют управлять состоянием динамически, обеспечивая прямую реакцию на пользовательские события и изменения интерфейса без лишней сложности.
Hyperapp делает Actions центральной частью архитектуры, обеспечивая компактный, чистый и предсказуемый способ управления состоянием и обработки событий в приложении.