![](https://habrastorage.org/files/347/fbd/883/347fbd8832e24e88873c653f45041eea.jpg)
Сначала о Flux
Что собой представляет Flux? Вкратце: это даже не паттерн, это больше способ организации архитектуры приложения. Состоит из store, dispatcher, view. Особенностью Flux является однонаправленная связь между компонентами системы посредством actions.
![](https://habrastorage.org/files/568/e7e/de6/568e7ede69044cbda6848e218cb622d2.png)
Взглянем подробнее на 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, может сигнализировать родителю, о происходящих в нем изменениях и действиях, которые совершает пользователь? Реализовать сигнализирование можно двумя способами:
- через callbacks, передавая их через props и обзывая событиями, например, onChange. Данная стратегия, хорошо подходит для разработки отдельных переиспользуемых компонентов интерфейса: кнопок, селектов, автокомплитов и тд.
- используя паттер 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)
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, но есть и другие. Например, здесь была статья на хабре про другой малоизвестный фреймворк, где устроено все несколько иначе.wheercool
05.11.2015 16:09Store – это далеко не модель. Модель, насколько мне известно, хранит образ сущности, например объект «Пользователь» с полем Name, Age и т.д.
То, что вы описываете называется пассивной моделью. В классическом MVC канонической принято считать моделью то как вы организовали Store.
На самом деле в какой-то статье читал, что в самом Facebook есть сторонники обоих подходовpragmadash
05.11.2015 16:16В статье википедии (по вашей ссылке) есть фраза:
… реагирует на запросы, изменяя своё состояние
Насколько я понимаю, Store не хранит и не изменяет свое состояние, он его запрашивает и перезапрашивает в случае изменения данных на удаленном ресурсе. Или я что-то не так понял?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?pragmadash
05.11.2015 16:52Но ваша интерпретация Flux очень интересная. А поясните пожалуйста, пример про 5 запросов от разных компонентов.
Я так понимаю, что у вас используется что то вроде Promise?
Ну в моем подходе везде используются Promises, но конкретно с этим кейсом немного сложнее все.
ua9msn
Я начитался про Flux, обнаружил Reflux, по ссылке оттуда решил посмотреть что такое Flummox, и обнаружил Redux. Вот, теперь внедряю.
А с вами абсолютно согласен. Паттерны и мозг никто не отменял.
ekubyshin
redux пока еще не смотрел, юзаю чистый react