Pull to refresh

Comments 44

Ну зачем же представлять Господа, как злого и мстительного тимлида, навязывающего всем свое мнение?)))
Ну или даже вот такой вопрос — зачем писать используя Flux и называть это MVC? По сути у вас все view обращаются к одной модели через контроллеры этих вьюх посредством кидания экшнов, а модель автоматически обновляет вьюхи… эм, ну то есть у вас однонаправленное движение данных, как и нужно в Flux.
А кто сказал, что однонаправленное движение противоречит MVC? Такое придумано далеко не во Flux и применяется давным давно.
простите, не туда откомментировал :)
А зачем строить MVC на редуксе с реактом когда их связка создана ради Flux-архитектуры? А если нет возможности использовать Flux то зачем использовать редукс когда можно использовать что-либо более MVC с реактом?

Мне кажется, что я использую связку React+Redux вполне стандартным образом. Просто я ввел некоторые ограничения, которые гарантируют, что все плюсы, которые дает нам Redux не будут сведены на нет. Про возможное убийство плюсов я писал.
Насчет "если нет возможности использовать Flux то зачем использовать редукс" не могу согласиться. Redux — всё-таки это не Flux (про отличия от предшественников можно почитать тут https://github.com/reactjs/redux/blob/master/docs/introduction/PriorArt.md )
Зачем строить MVC? Потому что плюсов масса, и потому что это легко сделать — посмотрите код всего приложения, там никаких кастомных решений нет — всё беру из коробки.

Ну вы и не строите здесь MVC, а просто используете терминологию. Причем тут MVC вообще? Тут он никак не подходит. Если проводить аналогию, React-компоненты — это View+Controller (с точки зрения UI), а с точки зрения Redux-приложения — уже редьюсеры/mapPropsToState — это «контроллер» (но даже язык не поворачивается это так называть). Модель — ее тут вообще нет. Есть состояние, и есть контейнер состояния (Redux), реализующий Flux-паттерн. И зачем пытаться подогнать это под совершенно иной и не имеющий отношение к делу паттерн? Какие плюсы в назывании всего этого MVC?

Вы говорите, что модели здесь вообще нет.


Описание модели из русской википедии:


Модель (англ. Model):

Предоставляет знания: данные и методы работы с этими данными;
Реагирует на запросы, изменяя своё состояние;
Не содержит информации, как эти знания можно визуализировать;

Экземпляр Store из Redux:
Предоставляет знания: данные и методы работы с этими данными — YES
Реагирует на запросы, изменяя своё состояние — YES
Не содержит информации, как эти знания можно визуализировать — YES


Не вижу противоречий.


Controller связывавает View и Model. Здесь всё стандартно


Дело в том, что React-компонент может выполнять все роли из MVC — хранить данные, обрабытывать их и рулить другими компонентами, может даже дергать функции дочерних компонентов через Refs. Из-за таких широких возможностей многие лепят архитектуру как попало. Я же предлагаю вариант наведения в коде порядка, спроецировав старые добрые принципы в новую реальность

Дело в том, что React-компонент может выполнять все роли из MVC
Вот поэтому тут не стоит даже упоминать MVC, чтобы избежать любой путаницы.

Если лезть в детали — Store не меняет свое состояние сам, и не содержит сам по себе никаких методов работы с этими данными. Более того, там могут храниться как данные приложения (domain data), так и различные аспекты состояния UI. Redux — это «state container», а не модель. И не пытается быть последней. Редьюсеры меняют любое состояние, и отнюдь не обязательно связанное с бизнес-логикой приложения. С очень большой натяжкой можно назвать всю эту часть «моделью», и то только для тех, кто вот без MVC вообще не может понять что за что отвечает. Но, как по мне, это изначально неверный способ думать об архитектуре Redux-приложений.
Если лезть в детали — Store не меняет свое состояние сам, и не содержит сам по себе никаких методов работы с этими данными

Если уж совсем грубо, то это ужасная «тонкая модель» из мира MVC (не академического, а того, который часто реализуют на практике). А компоненты на реакте — вьюшка и толстый контроллер.
Я понимаю, что хочется казаться модным и утверждать, что здесь нет ничего из поганого мира ооп, но то, что вы старательно даете старым вещам новые имена не делает эти вещи новыми.
Да Redux — это вообще не модель, ни тонкая, ни какая-то еще (в терминах привычных реализаций MVC).

Да не, модным никто и не пытается казаться, и кто-то говорил что-то про «поганый мир ООП» (я так не считаю)? Я только о том, что не нужно все под одну гребенку MVC, потому что так вроде бы проще. Элементов больше, стыки между M, V и C без натяжки не сделать, да и незачем.
Я еще раз внимательно перечитал ваш пост — да, вы на самом деле используете редукс так же как и предлагает документация, только называете все терминами MVC. Не могли бы вы привести пример использования middlewares в том же ключе MVC? Просто я в вашем коде вижу чистейший флюкс (ну хорошо, да, не флюкс а редукс, но все же) просто с подогнанными названиями из MVC которые очень хорошо легли на пример из вашей статьи. И в связи с этим ощущаю некий диссонанс :)

Насчет middlewares: я использую redux-thunk. Без проблем прикрутится redux-devtools, какой-нибудь логгер и т.д… По-идее middlewares не должны мешать


Пример использования redux-thunk:


function submit() {
   return function(dispatch, getState) {
      const state = getState();
      dispatch(reset());  
      request('/auth/', {send: {
          login : state.login,
          password : state.password
      }}).then(function() {
          router.push('/');
      }).catch(function() {
          window.alert("Auth failed")
      });
   }
}
При том, что статья полезная и шикарная, не могу согласиться, что называть это MVC — корректно. Да, провести аналогии можно, но не более. MVC — это подход, который подразумевает множество потоков данных между множеством моделей и отображений через множество контроллеров. Flux же — это идея о «едином источнике правды» и как следствие об однонаправленном потоке данных. Хоть Вы выше и говорите, что Redux не Flux, но это правда лишь от части. Redux реализует Flux (как идею), но не реализует её так же как эту идею реализует библиотека Flux. В общем и целом, я о том что нужно называть вещи своими именами.
MVC — это разделение на M, V и С. А если коротко, то — разделение данных и представления. Ничего больше в этом подходе не подразумевается.

То что подход многими реализуется через одно место, вовсе не означает, что это подразумевается подходом.
Не согласен с утверждением. MVC все же определяет конкретные блоки. Кроме того, в статье «лейблы» M, V и C вешаются на вполне конкретные вещи, так что стоит рассматривать паттерн именно в контексте конкретной реализации (а их у MVC может быть полно).
разделение данных и представления

Очень грубое упрощение. MVC про разделение бизнес-логики (с данными) и логики представления (может быть тоже со своими данными).

Тогда MVVM — тоже MVC? Document-Model — тоже MVC?
Redux — это не совсем MVC, но выполняет ту же функцию: разделяет данные, представления и изменения данных.

Не стоит делать MVC потому что это легко, лучше, наоборот, MVC — чтобы хоть как то организовать архитектуру и чтобы далее было легче.
Так «архитектуру организовывают» компонентный подход, Flux-паттерн (односторонний data-flow, предсказуемое управление состоянием), причем тут MVC-то?

Про "легко" и "MVC" я написал, потому что для реализации его принципов в связке React и Redux не нужно никаких надстроек, не нужно своего кастомного кода — нужно лишь придерживаться пары простых принципов, как раз для хорошей организации кода

UFO landed and left these words here
Если уж приложение растет, никто не запрещает сделать 20 редьюсеров. А так же, использование библиотек вроде normalizr и reselect подразумевается априори.
UFO landed and left these words here

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

UFO landed and left these words here

В случае календаря его внутреннее состояние — это открыт datepicker или закрыт, текущий выбранный месяц и год, режим показа (некоторые календари позволяют переходить в режим выбора месяца или года по клику по дате). Для такого компонента состояние — это нормально, и не нужно выносить его в application state. В то же время список дат из рабочего графика — это состояние внешнее по отношению к компоненту, это application state и его нужно хранить и обрабатывать редьюсерами.

UFO landed and left these words here

Я думаю, в календаре нужен коллбек на показ месяца. На сколько месяцев вперед нужно его загружать, сказать сложно.
Я не думаю, что тут есть чисто проблема для Реакта, для она будет одинакова для любого фреймворка — загружать график перед показом месяца.

При использовании Stateful-компонентов, чтобы достать их State, придется использовать Refs.

вы хотите зачем-то знать state дочерних компонентов? зачем использовать refs для того, чтобы читать this.state?

Я этого не хочу, но я видел, что так делают, а React это позволяет. Это одна из причин, которая заставила задуматься о том, как пресечь это на корню

Хранение каких-то данных в представлении или контроллере не противоречит MVC, а хранение данных представления или контроллера в модели — противоречит. Единственное хранилище данных в MVC-приложении означает, что у представления нет своих данных, в примере же данные у представления есть, собственно только они и есть, нет даже поля типа isAuthenticated, которое можно было бы отнести к модели.
UFO landed and left these words here
  1. Ставить рамки это хорошо. Чем жестче ограничения, тем однообразнее будет код.


  2. Да — я думаю, что state внутри компонента это плохая идея, и стоит избегать его использования. Единственный случай, когда это правда необходимо — это разработка компонента, который может работать в обоих, в Stateful и Stateless, режимах. Классический пример это React-овский Input. Он умеет Controlled/Uncontrolled режимы. И ведет себя сильно по-разному.


  3. tryAutoFill ничем не отличается от updateLogin. Т.е. Компонент знает, что какие-то callback-и будут, знает интерфейс, но не имеет представления о реализации


  4. "Умные" компоненты появляются только, когда лень реализовывать правильно.
    Не стоит загаживать хранилище такими вещами, иначе потом там сам черт ногу сломит.

Неужели вы ни разу не упирались в то, что с каким-то Stateful-компонентом со временным State не удается реализовать нужный сценарий, и приходится много переписывать?
Вас Undo/Redo не беспокоит? Или серверный рендеринг?
Проблемы не надуманы — они реально существуют

UFO landed and left these words here
Согласен почти со всем, но насчет локального state мне кажется, что ограничения можно сделать полегче. В частности, использовать state только тогда, когда данные в нем нужны только самому этому компоненту и его дочерним элементам. Если они становятся нужны где-то еще, то вынести их в основной store. Простой пример: в компоненте для вкладок номер текущей вкладки хранить в state, но если потребуется переключать вкладку извне, то вынести это в store. Весь рефакторинг будет заключаться в замене setState на dispatch и передаче добавленных в store данных по цепочке компонентов через props. Это может занять немного времени, но по-крайней мере это прямолинейная, рутинная работа, над которой не нужно думать (может быть можно даже сделать плагин для IDE, который будет делать это сам). А вот через ref такие проблемы решать — на самом деле антипаттерн.
UFO landed and left these words here
А можно описать пример посложнее? Например, как с помощью этой связки сделать таблицу с постраничной или бесконечной загрузкой? Сложность даже не в stateless-компонентах, а в том, как хранить модель (а точнее коллекцию моделей).
Ну теперь я по крайней мере точно вижу что это не MVC, т.к. модель хранит «filteringMode», т.е. параметр отображения. Ещё впечатляет огромный объём кода для такого простенького приложения. Но того о чём я спрашивал там нет и близко. Как быть если список todos придётся загружать частично, а потом подгружать по мере необходимости? А когда пользователь изменит настройки фильтрации/сортировки? А если их (элементы списка) спользуют другие представления (компоненты)?
UFO landed and left these words here

Насчет stateless и lifecycle: тут весьма неоднозначно. Сам компонент не знает в какой стадии жизненного цикла находится — из функции render и из других кастомных функций нельзя узнать в какой стадии жизненного цикла сейчас компонент.

UFO landed and left these words here
А как в этом MVC логику положить в модель? Это больше на какой-то VC похоже.
Sign up to leave a comment.

Articles