Global state management

Глобальное состояние в SPA может использоваться для упрощения создания комплексных приложений. Не зависимо от выбранного инструмента, само его наличие всегда увеличивает сложность приложения.

Какие есть готовые решения?

  • Redux (обычно для React)

  • ngrx для Angular (принципы работы Redux реализованные на базе RxJS + аннотации TypeScript)

  • MobX (альтернатива для React)

  • Vuex для Vue.js

Зачем заморачиваться?

Ключевое свойство, которым обладают большинство решений, это разделения кода фиксации (регистрации) события от его обработки. И это не просто разделение типа "вынесем в отдельный метод и будем его вызывать".

Свойства системы с глобальным состоянием

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

  • Одно и тоже событие может быть вызвано разными источниками

  • Одно и тоже событие может быть обработано разными подсистемами. Источники по прежнему не знают о существовании ни одной из них. Следовательно, эти подсистемы могут добавляться без изменения существующего кода компонентов. Это пересекается с аспектно-ориентированным программированием (AOP), концептами cross cutting concerns и middleware.

  • Вся бизнес логика обработки событий (а конкретно их влияния на глобальное состояние) сосредоточена в одном месте. Ни один компонент не может "втихую" изменить глобальное состояние, что бы это прошло "мимо истории событий"

Что в результате

  • Источниками изменений данных в глобальном хранилище могут быть разные компоненты

  • Разработчик может глобально (в одном месте) отслеживать все события, что инициируются их источниками. Для этого есть специальные расширения для браузера под каждую из систем. К примеру Redux Dev Tools.

  • Компоненты сами декларируют какие данные нужны для их работы. Если одна ветка (к примеру профиль пользователя) нужна нескольким компонентам, пусть даже в глубине дерева компонентов, они их получать без необходимости прокидывать данные через всех родителей аж от root компонента. При этом, сам компонент может и не знать, что он работает с глобальным состоянием (смотри react-redux).

  • Если данные меняться (к примеру тот-же профиль пользователя) об этом узнаю все подписанные на эту ветку (данные по ключю или пути, я-ля xpath, в глобальном состоянии) компоненты

  • Дефекты в поведении приложение у пользователей легко воссоздаются из "исходного состояния" и последующего прокручивание "истории событий".

Чем приходятся платить?

Когда источники событий и их обработчики разделены и не связаны друг с другом – появляется много "сопровождающего" кода. Теперь каждое, даже "мелкое" событие, надо описать. К примеру в виде его типа и наполнения (payload).

// somewere in store related folder
export ADD_TASK = 'ADD_TASK'

// somewhere in TaskPageComponnent (without react-redux)
store.dispatch({
  type: ADD_TASK
  payload: { name: 'Use Redux' }
})

И также описать обработчик этого события.

import ADD_TASK from 'actions'

taskReducer = (state, action) => {
    switch (action.type) {
        case ADD_TASK: 
            let tasks = [...state.tasks, action.payload]
            return {...state, tasks}
    }
} 

Last updated