Принципы организации состояния приложения

Состояние в Hyperapp — это центральная модель данных приложения, описывающая его текущий снимок в каждый момент времени. В отличие от тяжеловесных архитектур, здесь состояние организуется минималистично, но строго, что позволяет сохранять предсказуемость поведения интерфейса при росте сложности.

Архитектура Hyperapp опирается на принцип единого дерева состояния. Все данные, влияющие на отображение и логику, находятся в одном объекте state. Это исключает рассинхронизацию между разными частями приложения и упрощает анализ происходящего.

const state = {
  counter: 0,
  user: {
    name: "Ivan",
    authenticated: false
  }
}

Такое дерево не обязано быть плоским. Напротив, вложенная структура по доменам отражает реальную модель приложения и делает состояние семантически выразительным.

Неизменяемость как основа предсказуемости

Состояние в Hyperapp считается неизменяемым. Любое изменение приводит к созданию нового объекта состояния, а не к модификации существующего. Это правило не навязывается механизмами языка, но строго соблюдается архитектурно.

const actions = {
  increment: state => ({ counter: state.counter + 1 })
}

Функция действия возвращает новый фрагмент состояния, который будет слит с текущим. Отсутствие побочных эффектов в таких функциях делает поведение приложения детерминированным.

Действия как единственный способ изменения состояния

Изменение состояния происходит исключительно через действия (actions). Действие — это чистая функция, принимающая текущее состояние и аргументы, и возвращающая новый объект состояния или функцию для вычисления результата.

const actions = {
  login: user => state => ({
    user: {
      ...state.user,
      name: user.name,
      authenticated: true
    }
  })
}

Такой подход устраняет неявные изменения и формирует чёткую точку контроля над логикой приложения.

Локализация ответственности действий

Действия логически группируются по областям состояния. Это снижает связность и облегчает сопровождение. Часто структура actions повторяет структуру state.

const state = {
  todos: [],
  filter: "all"
}

const actions = {
  todos: {
    add: text => state => ({
      todos: state.todos.concat({ text, done: false })
    })
  },
  filter: {
    set: value => ({ filter: value })
  }
}

Такая симметрия делает код самодокументируемым.

Побочные эффекты и изоляция логики

Для работы с асинхронными операциями Hyperapp использует эффекты (effects). Они отделяются от логики изменения состояния, сохраняя чистоту действий.

const fetchUser = id => [
  state => state,
  [fetch, {
    url: `/api/user/${id}`,
    action: actions.userLoaded
  }]
]

Состояние не зависит от конкретных источников данных, а эффекты становятся заменяемыми и тестируемыми единицами.

Производное состояние вместо хранения вычисляемых данных

Данные, которые могут быть вычислены на основе существующего состояния, не хранятся явно. Это предотвращает дублирование и логические ошибки.

const completedTodos = state =>
  state.todos.filter(todo => todo.done)

Производное состояние вычисляется на этапе рендеринга или в селекторах и не загрязняет основное дерево данных.

Разделение глобального и локального состояния

Hyperapp допускает использование локального состояния на уровне компонентов, но фундаментальная логика остаётся в глобальном состоянии приложения. Локальные данные применяются для краткоживущих или чисто визуальных состояний, таких как фокус, временные значения ввода или анимационные флаги.

Это разграничение снижает шум в глобальном состоянии и подчёркивает его роль как модели предметной области.

Композиция состояния и масштабирование

При росте приложения состояние и действия легко компонуются из независимых модулей. Каждый модуль описывает собственное поддерево состояния и набор действий, которые затем объединяются в корневой конфигурации.

const state = {
  auth: authState,
  dashboard: dashboardState
}

const actions = {
  auth: authActions,
  dashboard: dashboardActions
}

Отсутствие скрытых зависимостей делает масштабирование линейным по сложности.

Сериализация и воспроизводимость

Чистота состояния позволяет без дополнительных усилий сериализовать его для сохранения, восстановления или отладки. Воспроизведение состояния гарантирует идентичный результат рендеринга, что особенно важно для тестирования и анализа ошибок.

Тестируемость как следствие архитектуры

Действия и селекторы легко тестируются изолированно, так как представляют собой обычные функции без скрытого контекста. Состояние на входе и результат на выходе полностью описывают поведение логики.

Такой подход превращает организацию состояния из технической необходимости в инструмент строгого контроля над сложностью приложения.