В Hyperapp состояние приложения (state) рассматривается
как неизменяемый объект. Любые изменения не производятся напрямую, а
создаются новые объекты состояния на основе предыдущего. Это
позволяет:
Пример структуры состояния:
const state = {
counter: 0,
todos: [
{ id: 1, text: "Изучить Hyperapp", done: false },
{ id: 2, text: "Написать статью", done: false }
]
};
Изменение counter через мутацию напрямую:
state.counter = state.counter + 1; // НЕПРАВИЛЬНО
Правильный способ с использованием чистой функции:
const increment = state => ({ ...state, counter: state.counter + 1 });
В этом примере создаётся новый объект состояния с обновлённым
значением counter, а оригинальный объект остаётся
неизменным.
Чистая функция — это функция, которая:
Применение чистых функций в Hyperapp позволяет:
Пример чистой функции в Hyperapp:
const toggleTodo = id => state => ({
...state,
todos: state.todos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
)
});
Здесь функция toggleTodo создаёт новый массив
todos, где только выбранный элемент изменён, остальные
остаются неизменными. Исходный массив state.todos не
модифицируется.
В Hyperapp все изменения состояния выполняются через actions. Action — это функция, которая принимает текущее состояние и возвращает новое. Action должен быть чистой функцией:
const addTodo = text => state => ({
...state,
todos: [
...state.todos,
{ id: Date.now(), text, done: false }
]
});
Ключевые моменты:
spread для создания нового
массива todos.Hyperapp использует виртуальный DOM для эффективного обновления реального DOM. Важный аспект:
Пример правильного обновления DOM через неизменяемость:
const state = { counter: 0 };
const increment = state => ({ ...state, counter: state.counter + 1 });
app({
init: state,
view: state => h("div", {}, `Counter: ${state.counter}`),
node: document.getElementById("app"),
actions: { increment }
});
При каждом вызове increment создаётся новый объект
состояния, что гарантирует корректное обновление DOM.
Когда состояние вложенное, важно создавать копии на каждом уровне. Прямая мутация вложенных объектов нарушает принцип неизменяемости.
Пример с вложенными объектами:
const state = {
user: { name: "Alice", settings: { theme: "dark", notifications: true } }
};
// Неправильно:
state.user.settings.theme = "light";
// Правильно:
const updateTheme = theme => state => ({
...state,
user: {
...state.user,
settings: {
...state.user.settings,
theme
}
}
});
Использование оператора spread на каждом уровне
обеспечивает полное соблюдение принципа неизменяемости.
Придерживаясь этих принципов, Hyperapp позволяет создавать приложения с предсказуемым поведением, легко тестируемой логикой и эффективным обновлением интерфейса.