Расскажу об еще одной интерпретации Flux, а точнее о новом подходе в разработке интерфейсов — Not a Flux. Предполагается, что читатель хотя бы прочитал документацию о Flux.



Сначала о Flux


Что собой представляет Flux? Вкратце: это даже не паттерн, это больше способ организации архитектуры приложения. Состоит из store, dispatcher, view. Особенностью Flux является однонаправленная связь между компонентами системы посредством actions.



Взглянем подробнее на FLUX со стороны react и MVC.

Согласно философии react, выделяют controller view и view.

Controller view это родитель для других view, который отвечает за логику отрисовки его детей, получает данные из модели и отдает их детям в props. При этом инженеры Facebook говорят, что во Flux отсутствует controller. Эммм… тогда кто же рисует view, кто определяет какой view необходимо отобразить? Случаем это делает не Controller view?

В модели MVC — это контроллер, который общается с моделью, получает от нее данные и рисует view. Иными словами, контроллер это прослойка, которая работает с данными из модели, передает их во вью и отрисовывает конкретные view, в конкретный момент времени в зависимости от внешних условий. Что соответствует также философии разделения на компоненты. Не будем говорить о тех тупых контроллерах, которые делают всю работу или о тех тупых вью, которые еще и знают о модели.

Stateless View или просто VIew, что же это такое? В новом react появилась возможность создавать их еще проще, объявляя в модуле обычную функцию, которая возвращает шаблон jsx, т.е. в модели mvc это V (view). Называются они stateless functional components.

В свою очередь во вью приходит модель данных в props, с которыми эта View работает, своего рода View Model, т.е. специально подготовленные данные, которые нужны для конкретной View.

С данными Flux работает через центральное хранилище, называемое Store. В свою очередь это и есть M (Model) в MVC паттерне. Отличие состоит в том, что модель знает о dispatcher, но об этом чуть позже и одновременно Store — является центральным хранилищем для всего и вся, а также содержит некий state приложения. А также, инженеры Facebook, говорят, что Store содержит логику, но какую?

Таким образом функцию контроллера в MVC размазали между controller view и Store. Кто работал с Backbone или с другими фреймфорками, скорее всего сталкивался с проблемой необходимости хранения состояния приложения. Решить данную проблему можно разными путями, но в большинстве случаев за это отвечал либо главный контроллер, либо urls, либо localStorage.

Каким же образом children view, может сигнализировать родителю, о происходящих в нем изменениях и действиях, которые совершает пользователь? Реализовать сигнализирование можно двумя способами:

  1. через callbacks, передавая их через props и обзывая событиями, например, onChange. Данная стратегия, хорошо подходит для разработки отдельных переиспользуемых компонентов интерфейса: кнопок, селектов, автокомплитов и тд.
  2. используя паттер Mediator посредством events, которые в реакте назвали actions. Да, именно mediator в паттерне pub-sub выполняет роль некой трубы, куда сыпятся куча ивентов, а слушатели могут подписываться на нужные ивенты и работать с ними. В FLUX это называется Dispatcher.

Об Actions


Action согласно философии react состоит из названия этого действия и самих данных, что в свою очередь напоминает обычный объект event в pub-sub.

Теперь к практике


Рассмотрим обычный пример TODO на сайте Flux. Там отчетливо видно, что выделяется контроллер, который координирует все действия происходящие в диспетчере, в нужный момент лезет в store (модель), точнее подписывается на события, получает от нее данные, опять же через события pub-sub и кидает их нужным потомкам через props. Единственное, что не понятно, так это зачем обычной кнопке знать о Dispatcher и сигнализировать о своих действиях? Как потом можно переиспользовать эту кнопку в других View? Куда гибче, было бы использовать callback, а уже в parent View кидать, что-то в Dispatcher.

Так что же такое Flux? Flux — это не что иное, как комбинация структурного паттерна организации кода MVC/MVVM и паттерна взаимодействия Mediator. То, что это связь однонаправленная это и так ясно, зачем потомкам контроллера знать о модели, иначе их нельзя будет переиспользовать в других местах.

Пример из жизни


В следующей статье расскажу о применении Not a Flux способа в реальном проекте на react.

P.S.


Предлагаю всем, кто считает Flux новшеством и ищет в интернетах различные статьи о Flux, наподобие, Flux for stupids, использовать совершенно новый паттерн Not a Flux, состоящего из двух компонентов: Brain и Design patterns.

Какой из этого можно сделать вывод? На мой взгляд, надо изучать не flux и как его успешно применять в приложениях на react, а изучать основные паттерны, которые являются основополагающими в разработке ПО, например, структурные паттерны, паттерны взаимодействия, паттерны создания объектов (фабрики) и др. Flux это просто пример, как зная эти паттерны, можно наладить взаимодействие между компонентами и организовать приложение.

Критика по делу и указание на неточности приветствуется.

Литература


Кому интересно, рекомендую к прочтению пару книг (ссылки сами знаете где найти), если кто не читал их:

  • Learn Javascript Design Patterns от Addy Osmani
  • Javascript Patterns от Stoyan Stefanov
  • О ReactJS
  • О Flux

* Все картинки взяты на просторах интернета

Комментарии (7)


  1. ua9msn
    05.11.2015 12:29
    +3

    Я начитался про Flux, обнаружил Reflux, по ссылке оттуда решил посмотреть что такое Flummox, и обнаружил Redux. Вот, теперь внедряю.
    А с вами абсолютно согласен. Паттерны и мозг никто не отменял.


    1. ekubyshin
      06.11.2015 10:12

      redux пока еще не смотрел, юзаю чистый react


  1. pragmadash
    05.11.2015 13:29

    Мне лично кажется вы не до конца разобрались во Flux.

    Dispatcher здесь это не просто посредник, который «пробрасывает» события из View в Store, он делает это безопасно. Живой пример: у вас есть 5 компонентов, привязанных к одному Store, которые условно одновременно обновляются на странице и делают запрос за данными в один и тот же Store. Dispatcher, в таком случае, ответственен за то, чтобы пропустить запрос данных только одного компонента, получить для него ответ и сдублировать 4-м остальным. Именно поэтому он называется Dispatcher. И это только один пример, их может быть масса.

    Store – это далеко не модель. Модель, насколько мне известно, хранит образ сущности, например объект «Пользователь» с полем Name, Age и т.д. Store же хранит логику «как получить пользователя с удаленного сервера», а также логику всех возможных действий «Actions» с этим пользователем, например, «как сделать запрос удаления пользователя на сервере». То есть, проще говоря, Store как раз абстракция для загрузки модели с сервера и для редактирования этой модели на сервере.

    Вы также не забывайте, что React+Flux это всего лишь одна реализация принципа, описанного инженерами из Facebook, но есть и другие. Например, здесь была статья на хабре про другой малоизвестный фреймворк, где устроено все несколько иначе.


    1. wheercool
      05.11.2015 16:09

      Store – это далеко не модель. Модель, насколько мне известно, хранит образ сущности, например объект «Пользователь» с полем Name, Age и т.д.

      То, что вы описываете называется пассивной моделью. В классическом MVC канонической принято считать моделью то как вы организовали Store.
      На самом деле в какой-то статье читал, что в самом Facebook есть сторонники обоих подходов


      1. pragmadash
        05.11.2015 16:16

        В статье википедии (по вашей ссылке) есть фраза:

        … реагирует на запросы, изменяя своё состояние

        Насколько я понимаю, Store не хранит и не изменяет свое состояние, он его запрашивает и перезапрашивает в случае изменения данных на удаленном ресурсе. Или я что-то не так понял?


        1. wheercool
          05.11.2015 16:49

          Не совсем понял фразу по поводу того, что Store не хранит свое состояние.
          Т.е. вы используете Store как абстракцию, чтобы делать запросы к серверу? Честно говоря интересный подход :)
          Но во всех презентациях и примерах от Facebook Store хранит состояние (да и само название как бы намекает)

          When a user interacts with a React view, the view propagates an action through a central dispatcher, to the various stores that hold the application's data and business logic, which updates all of the views that are affected.

          Но ваша интерпретация Flux очень интересная. А поясните пожалуйста, пример про 5 запросов от разных компонентов.
          Я так понимаю, что у вас используется что то вроде Promise?


          1. pragmadash
            05.11.2015 16:52

            Но ваша интерпретация Flux очень интересная. А поясните пожалуйста, пример про 5 запросов от разных компонентов.
            Я так понимаю, что у вас используется что то вроде Promise?


            Ну в моем подходе везде используются Promises, но конкретно с этим кейсом немного сложнее все.