Однонаправленный поток данных

Однонаправленный поток данных (unidirectional data flow) является фундаментальной концепцией архитектуры приложений, построенных на Hyperapp. Он обеспечивает предсказуемость состояния, упрощает отладку и повышает читаемость кода. В Hyperapp этот поток строится вокруг трёх ключевых элементов: state, actions и view.


State: централизованное состояние приложения

state представляет собой единый источник истины для всего приложения. Он описывает текущее состояние интерфейса и данных, с которыми работает приложение. В Hyperapp state реализуется как обычный JavaScript-объект:

const state = {
  count: 0,
  user: { name: "Alice", loggedIn: false },
  todos: []
};

Ключевые моменты:

  • Все данные находятся в одном месте.
  • Изменения state происходят исключительно через действия (actions).
  • Доступ к state из view осуществляется напрямую, но изменение состояния происходит строго контролируемым образом.

Actions: единственный способ изменять state

actions — функции, которые описывают, как состояние должно изменяться. Они принимают текущее состояние и аргументы, возвращая новый объект состояния. Это обеспечивает чистоту и предсказуемость изменений:

const actions = {
  increment: state => ({ count: state.count + 1 }),
  login: (state, payload) => ({ user: { ...state.user, loggedIn: true, name: payload.name } }),
  addTodo: (state, payload) => ({ todos: [...state.todos, payload] })
};

Особенности:

  • Actions всегда возвращают новый объект состояния, не изменяя старый.
  • Их можно комбинировать, создавая цепочки сложных изменений.
  • Любое изменение state через actions автоматически инициирует повторный рендер view.

View: отображение состояния

view — это функция, которая превращает текущее состояние и действия в виртуальный DOM. Она не изменяет state напрямую, а лишь описывает интерфейс:

const view = (state, actions) => (
  h("div", {}, [
    h("h1", {}, `Счет: ${state.count}`),
    h("button", { onclick: () => actions.increment() }, "Увеличить"),
    h("ul", {}, state.todos.map(todo => h("li", {}, todo)))
  ])
);

Важные моменты:

  • view является чистой функцией: одинаковые входные данные дают одинаковый результат.
  • Она получает state и actions как параметры, что исключает побочные эффекты.
  • Любое изменение через actions автоматически перерисовывает соответствующие части интерфейса.

Поток данных

В Hyperapp поток данных строится строго по принципу:

state → view → действия пользователя → actions → новый state → view

Детали работы:

  1. Инициализация: Hyperapp создаёт начальный state.
  2. Рендер: view преобразует state в виртуальный DOM и отображает его на странице.
  3. Взаимодействие пользователя: события (клик, ввод) вызывают actions.
  4. Изменение состояния: actions возвращают новый объект state.
  5. Обновление интерфейса: Hyperapp сравнивает старый и новый виртуальный DOM и обновляет только изменившиеся части.

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


Преимущества однонаправленного потока

  • Простота отладки: каждое изменение состояния проходит через actions, что облегчает отслеживание ошибок.
  • Предсказуемость: интерфейс всегда отображает актуальное состояние state.
  • Масштабируемость: добавление новых функциональностей не ломает существующий поток данных.
  • Тестируемость: actions можно легко тестировать как чистые функции без UI.

Связь с компонентной архитектурой

Hyperapp поддерживает модульный подход, позволяя разделять state и actions на отдельные модули для разных частей приложения. При этом принцип однонаправленного потока сохраняется:

const todosModule = {
  state: { todos: [] },
  actions: {
    add: (state, payload) => ({ todos: [...state.todos, payload] })
  }
};

const appState = { ...todosModule.state, count: 0 };
const appActions = { ...todosModule.actions, increment: state => ({ count: state.count + 1 }) };

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


Итоговая структура Hyperapp-приложения

Основные элементы, формирующие однонаправленный поток:

  1. State — единый объект, отражающий текущее состояние.
  2. Actions — функции, изменяющие state предсказуемым образом.
  3. View — функция, отображающая state и реагирующая на actions.
  4. Event loop — обработка пользовательских действий через actions.

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