Зачем использовать Redux поверх Facebook Flux?

Я прочитал этот ответ, сокращая шаблон, посмотрел несколько примеров GitHub и даже немного попробовал редукс (приложения todo).

Как я понимаю, официальные мотивы приведения к редуксу дают плюсы по сравнению с традиционными архитектурами MVC. НО это не дает ответа на вопрос:

Почему вы должны использовать Redux поверх Facebook Flux?

Это только вопрос стилей программирования: функциональный против нефункционального? Или вопрос в способностях / инструментах разработки, которые следуют из подхода редукса? Может масштабирование? Или тестирование?

Прав ли я, если скажу, что редукс - это поток для людей, которые приходят с функциональных языков?

Чтобы ответить на этот вопрос, вы можете сравнить сложность точек мотивации реализации редукса на потоке против редукса.

Вот побудительные мотивы от официальных побудительных мотивов:

  1. Обработка оптимистичных обновлений (насколько я понимаю, это вряд ли зависит от 5-го пункта. Сложно ли реализовать это в Facebook Flux?)
  2. Рендеринг на сервере (Facebook Flux также может сделать это. Есть ли преимущества по сравнению с Redx?)
  3. Извлечение данных перед выполнением переходов по маршруту (Почему это невозможно сделать в Facebook Flux? В чем преимущества?)
  4. Горячая перезагрузка (это возможно с React Hot Reload. Зачем нам нужен редукс?)
  5. Отменить / Повторить функциональность
  6. Любые другие точки? Как постоянное состояние...

8 ответов

Решение

Автор Redux здесь!

Redux ничем не отличается от Flux. В целом, он имеет ту же архитектуру, но Redux может сократить некоторые сложности, используя функциональную композицию, в которой Flux использует регистрацию обратного вызова.

В Redux нет принципиальной разницы, но я считаю, что она делает некоторые абстракции более легкими или, по крайней мере, возможными для реализации, которые было бы трудно или невозможно реализовать в Flux.

Состав редуктора

Взять, к примеру, нумерацию страниц. Мой пример Flux + React Router обрабатывает нумерацию страниц, но код для этого ужасен. Одна из причин, по которой это ужасно, заключается в том, что Flux делает неестественным повторное использование функциональности в разных магазинах. Если двум хранилищам нужно обрабатывать нумерацию страниц в ответ на разные действия, им либо нужно наследовать от общего базового хранилища (плохо! Вы привязываетесь к конкретному дизайну, когда используете наследование), либо вызывать функцию из обработчика, который нужно будет как-то работать в частном состоянии магазина Flux. Все это грязно (хотя определенно в области возможного).

С другой стороны, с Redux нумерация страниц естественна благодаря составу редуктора. Это редукторы, так что вы можете написать фабрику редукторов, которая генерирует редукторы нумерации страниц, а затем использовать их в своем дереве редукторов. Ключ к тому, почему это так просто, заключается в том, что в Flux хранилища плоские, а в Redux редукторы могут быть вложены с помощью функциональной компоновки, как и компоненты React.

Этот шаблон также включает замечательные функции, такие как отмены / повторного выполнения без пользовательского кода. Можете ли вы представить, что подключение Undo/Redo к приложению Flux представляет собой две строки кода? Едва. С Redux это - снова, благодаря шаблону композиции редуктора. Я должен подчеркнуть, что в этом нет ничего нового - это образец, впервые описанный и подробно описанный в Elm Architecture, который сам был под влиянием Flux.

Рендеринг сервера

Люди хорошо выполняли рендеринг на сервере с помощью Flux, но, увидев, что у нас есть 20 библиотек Flux, каждая из которых пытается сделать процесс рендеринга на сервере "более простым", возможно, у Flux есть некоторые неровности на сервере. Правда в том, что Facebook не делает много рендеринга на серверах, поэтому они не очень беспокоятся об этом и полагаются на экосистему, чтобы сделать это проще.

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

В Flux по-прежнему есть следующие проблемы, которые вам нужно решить (самостоятельно или с помощью вашей любимой библиотеки Flux, такой как Flummox или Alt):

  • Если магазины являются классами, как мне создавать и уничтожать их с помощью диспетчера для каждого запроса? Когда я регистрирую магазины?
  • Как мне гидрировать данные из магазинов, а затем повторно скопировать их на клиенте? Нужно ли реализовывать специальные методы для этого?

По общему признанию, фреймворки Flux (не vanilla Flux) имеют решения этих проблем, но я нахожу их слишком сложными. Например, Flummox просит вас реализовать serialize() а также deserialize() в ваших магазинах. Alt решает эту проблему лучше, предоставляя takeSnapshot() это автоматически сериализует ваше состояние в дереве JSON.

Redux идет еще дальше: поскольку существует только один магазин (управляемый многими редукторами), вам не нужен специальный API для управления (ре) гидратацией. Вам не нужно "очищать" или "увлажнять" магазины - есть только один магазин, и вы можете прочитать его текущее состояние или создать новый магазин с новым состоянием. Каждый запрос получает отдельный экземпляр магазина. Узнайте больше о рендеринге сервера с помощью Redux.

Опять же, это случай чего-то возможного как в Flux, так и в Redux, но библиотеки Flux решают эту проблему, вводя тонну API и соглашений, и Redux даже не нужно ее решать, потому что у нее нет такой проблемы в Первое место благодаря концептуальной простоте.

Опыт разработчика

На самом деле я не собирался делать Redux популярной библиотекой Flux - я написал ее, когда работал над докладом ReactEurope о горячей перезагрузке с путешествиями во времени. У меня была одна главная цель: сделать возможным изменение кода редуктора на лету или даже "изменить прошлое", перечеркнув действия, и увидеть, как состояние пересчитывается.

Я не видел ни одной библиотеки Flux, которая могла бы сделать это. React Hot Loader также не позволяет вам этого делать - на самом деле он ломается, если вы редактируете хранилища Flux, потому что он не знает, что с ними делать.

Когда Redux необходимо перезагрузить код редуктора, он вызывает replaceReducer() и приложение запускается с новым кодом. В Flux данные и функции запутаны в хранилищах Flux, поэтому вы не можете "просто заменить функции". Более того, вам придется как-то перерегистрировать новые версии с помощью Dispatcher - чего у Redux даже нет.

экосистема

Redux имеет богатую и быстрорастущую экосистему. Это потому, что он предоставляет несколько точек расширения, таких как промежуточное ПО. Он был разработан с учетом вариантов использования, таких как ведение журнала, поддержка Promises, Observables, маршрутизация, проверка неизменяемости, проверка сохраняемости и т. Д. Не все из них окажутся полезными, но приятно иметь доступ к набору инструментов, которые можно легко комбинировать для совместной работы.

Простота

Redux сохраняет все преимущества Flux (запись и воспроизведение действий, однонаправленный поток данных, зависимые мутации) и добавляет новые преимущества (простая отмена, горячая перезагрузка) без использования Dispatcher и регистрации магазина.

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

В отличие от большинства библиотек Flux, поверхность Redux API крошечная. Если вы удалите предупреждения разработчика, комментарии и проверки работоспособности, это будет 99 строк. Нет сложного асинхронного кода для отладки.

Вы действительно можете прочитать его и понять все о Redux.


Смотрите также мой ответ о минусах использования Redux по сравнению с Flux.

В Quora кто-то говорит:

Прежде всего, полностью возможно написать приложения с React без Flux.

Также на этой визуальной диаграмме, которую я создал, показан краткий обзор обоих, возможно, быстрый ответ для людей, которые не хотят читать все объяснение: Flux против Redux

Но если вам все еще интересно узнать больше, читайте дальше.

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

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

Если вы начнете непосредственно с Redux, вы можете столкнуться с чрезмерно сложным кодом, который сложнее поддерживать, и с еще большим количеством ошибок, чем без Redux.

Из документов Redux:

мотивация
Поскольку требования к одностраничным приложениям JavaScript становятся все более сложными, наш код должен управлять большим количеством состояний, чем когда-либо прежде. Это состояние может включать ответы сервера и кэшированные данные, а также локально созданные данные, которые еще не были сохранены на сервере. Состояние пользовательского интерфейса также усложняется, поскольку нам необходимо управлять активными маршрутами, выбранными вкладками, счетчиками, элементами управления разбиением на страницы и так далее.

Управлять этим постоянно меняющимся состоянием сложно. Если модель может обновить другую модель, то представление может обновить модель, которая обновит другую модель, и это, в свою очередь, может привести к обновлению другого представления. В какой-то момент вы больше не понимаете, что происходит в вашем приложении, поскольку вы потеряли контроль над тем, когда, почему и как его состояние. Когда система непрозрачна и недетерминирована, трудно воспроизвести ошибки или добавить новые функции.

Как будто это не было достаточно плохо, рассмотрите новые требования, становящиеся общими при разработке передового продукта. Как разработчики, от нас ожидают оптимистичные обновления, рендеринг на стороне сервера, выборка данных перед выполнением переходов по маршруту и ​​так далее. Мы пытаемся справиться со сложностью, с которой нам никогда не приходилось сталкиваться прежде, и мы неизбежно задаем вопрос: пора ли сдаваться? Ответ - нет.

С этой сложностью трудно справиться, поскольку мы смешиваем две концепции, которые человеческому разуму очень трудно рассуждать: мутация и асинхронность. Я называю их Mentos и Coke. Оба могут быть хороши, когда разделены, но вместе они создают беспорядок. Такие библиотеки, как React, пытаются решить эту проблему на уровне представления, удаляя как асинхронность, так и прямые манипуляции с DOM. Однако управление состоянием ваших данных остается за вами. Это где Redux приходит.

Следуя по стопам Flux, CQRS и Event Sourcing, Redux пытается сделать изменения состояния предсказуемыми, налагая определенные ограничения на то, как и когда могут происходить обновления. Эти ограничения отражены в трех принципах Redux.

Также из документов Redux:

Основные понятия
Сам Redux очень прост.

Представьте, что состояние вашего приложения описывается как простой объект. Например, состояние приложения todo может выглядеть так:

{
  todos: [{
    text: 'Eat food',
    completed: true
  }, {
    text: 'Exercise',
    completed: false
  }],
  visibilityFilter: 'SHOW_COMPLETED'
}

Этот объект похож на "модель" за исключением того, что здесь нет сеттеров. Это связано с тем, что различные части кода не могут произвольно изменять состояние, что приводит к трудным для воспроизведения ошибкам.

Чтобы что-то изменить в состоянии, нужно отправить действие. Действие - это простой объект JavaScript (обратите внимание, как мы не представляем никакой магии?), Который описывает, что произошло. Вот несколько примеров действий:

{ type: 'ADD_TODO', text: 'Go to swimming pool' }
{ type: 'TOGGLE_TODO', index: 1 }
{ type: 'SET_VISIBILITY_FILTER', filter: 'SHOW_ALL' }

Благодаря тому, что каждое изменение описывается как действие, мы можем четко понимать, что происходит в приложении. Если что-то изменилось, мы знаем, почему это изменилось. Действия похожи на крошки от того, что произошло. Наконец, чтобы связать состояние и действия вместе, мы пишем функцию, называемую редуктором. Опять же, ничего волшебного в этом нет - это просто функция, которая принимает состояние и действие в качестве аргументов и возвращает следующее состояние приложения. Было бы сложно написать такую ​​функцию для большого приложения, поэтому мы пишем меньшие функции, управляющие частями состояния:

function visibilityFilter(state = 'SHOW_ALL', action) {
  if (action.type === 'SET_VISIBILITY_FILTER') {
    return action.filter;
  } else {
    return state;
  }
}

function todos(state = [], action) {
  switch (action.type) {
  case 'ADD_TODO':
    return state.concat([{ text: action.text, completed: false }]);
  case 'TOGGLE_TODO':
    return state.map((todo, index) =>
      action.index === index ?
        { text: todo.text, completed: !todo.completed } :
        todo
   )
  default:
    return state;
  }
}

И мы пишем еще один редуктор, который управляет полным состоянием нашего приложения, вызывая эти два редуктора для соответствующих ключей состояния:

function todoApp(state = {}, action) {
  return {
    todos: todos(state.todos, action),
    visibilityFilter: visibilityFilter(state.visibilityFilter, action)
  };
}

Это в основном вся идея Redux. Обратите внимание, что мы не использовали никаких API Redux. Он поставляется с несколькими утилитами для упрощения этого шаблона, но основная идея заключается в том, что вы описываете, как ваше состояние обновляется с течением времени в ответ на объекты действий, и 90% кода, который вы пишете, - это просто обычный JavaScript, без использования Redux. сам по себе, его API, или любая магия.

Возможно, вам лучше всего начать с прочтения этого поста Дэном Абрамовым, где он обсуждает различные реализации Flux и их компромиссы в то время, когда он писал лексем: Эволюция фреймворков Flux

Во-вторых, на странице с мотивациями, на которую вы ссылаетесь, на самом деле не столько обсуждаются мотивы Redux, сколько мотивы, стоящие за Flux (и React). " Три принципа" более специфичны для Redux, но все же не имеют отношения к отличиям реализации от стандартной архитектуры Flux.

По сути, Flux имеет несколько хранилищ, которые вычисляют изменение состояния в ответ на взаимодействия пользовательского интерфейса /API с компонентами и транслируют эти изменения как события, на которые могут подписаться компоненты. В Redux есть только один магазин, на который подписывается каждый компонент. IMO, по крайней мере, кажется, что Redux еще больше упрощает и унифицирует поток данных, объединяя (или сокращая, как сказал бы Redux) поток данных обратно к компонентам - тогда как Flux концентрируется на объединении другой стороны потока данных - модель.

Я один из первых, кто внедрил одностраничное приложение среднего размера, используя библиотеку Facebook Flux.

Поскольку я немного опаздываю к разговору, я просто укажу, что, несмотря на мои лучшие надежды, Facebook, похоже, считает, что их реализация Flux является доказательством концепции, и он никогда не получал того внимания, которого заслуживает.

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

Мы решили, что двигаясь вперед, мы переедем в Redux, и я предлагаю вам сделать то же самое;)

Вот простое объяснение Redux над Flux. Redux не имеет диспетчера. Он опирается на чистые функции, называемые редукторами. Для этого не нужен диспетчер. Каждое действие обрабатывается одним или несколькими редукторами для обновления одного хранилища. Поскольку данные неизменны, редукторы возвращают новое обновленное состояние, которое обновляет хранилище

Для получения дополнительной информации http://www.prathapkudupublog.com/2017/04/flux-vs-redux.html

Я довольно долго работал с Flux, а теперь довольно долго использую Redux. Как отметил Дэн, обе архитектуры не так уж отличаются. Дело в том, что Redux делает вещи проще и чище. Он учит вас нескольким вещам поверх Flux. Как, например, Flux является прекрасным примером потока данных в одном направлении. Разделение задач, где у нас есть данные, их манипуляции и слой представления разделены. В Redux мы имеем то же самое, но мы также узнаем об неизменности и чистых функциях.

От нового усыновителя реагирования / избыточности, переходящего с (несколько лет) ExtJS в середине 2018 года:

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

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

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

Он был гораздо более интуитивным, чем ванильный редукс, он вырезал 90% стандартного шаблона и сократил 75% времени, которое я тратил на редукс (что, я думаю, должна делать библиотека), я смог получить пару корпоративных приложений собирается прямо сейчас.

Он также работает с тем же редукционным инструментом. Это хорошая статья, которая охватывает некоторые из преимуществ.

Таким образом, для всех, кто прибыл в эту публикацию SO, ищущую "более простую редукцию", я рекомендую попробовать ее как простую альтернативу редуксу со всеми преимуществами и 1/4 от стандартного.

Flux - это шаблон, а Redux - это библиотека.

Flux - причудливое название для шаблона наблюдателя, немного измененного для соответствия React, но Facebook выпустил несколько инструментов, помогающих реализовать шаблон Flux, поэтому разница между этими инструментами заключается в следующем (обычно это называют Flux).) и используя Redux.

И у Flux, и у Redux есть действия. Действия можно сравнить с событиями (или с какими событиями запуска). В Flux действие - это простой объект JavaScript, и это тоже случай по умолчанию в Redux, но при использовании промежуточного программного обеспечения Redux действия также могут быть функциями и обещаниями.

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

Flux имеет одного диспетчера, и все действия должны проходить через этого диспетчера. Это одноэлементный объект. Приложение Flux не может иметь несколько диспетчеров. Это необходимо, потому что приложение Flux может иметь несколько хранилищ, а зависимости между этими хранилищами нуждаются в одном диспетчере, который является диспетчером.

Redux не имеет диспетчерской сущности. Вместо этого в хранилище встроен процесс диспетчеризации. В хранилище Redux представлено несколько простых API-функций, одна из которых - диспетчеризация действий.

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

В Redux логика того, что делать с данными на основе полученных действий, заключается в функции-редукторе, которая вызывается для каждого отправляемого действия (через API хранилища). Нельзя определить магазин без функции редуктора. Редуктор Redux - это простая функция, которая получает предыдущее состояние и одно действие и возвращает новое состояние на основе этого действия. В приложении Redux вы можете разделить ваш редуктор на более простые функции, как если бы вы делали это с любой другой функцией. Самый умный игрок в Redux - это редуктор.

В Redux также не так много гибкости в отношении того, что выставлять как состояние магазина. Redux просто выставит все, что вернуло из магазина редуктор. Это одно ограничение.

Другое большее ограничение заключается в том, что состояние магазина не может быть изменяемым (или действительно не должно быть). В Flux такого ограничения нет, вы можете изменять состояние по своему желанию. Неизменность состояния в Redux легко достигается благодаря чистым функциям редукторов (без побочных эффектов). Редукторы Redux всегда копируют полученное состояние и возвращают измененную версию копии состояния, а не сам исходный объект. Хотя это большое ограничение, оно делает жизнь намного проще в долгосрочной перспективе.

Согласно этой статье: https://medium.freecodecamp.org/a-realworld-comparison-of-front-end-frameworks-with-benchmarks-2019-update-4be0d3c78075

Вам лучше использовать MobX для управления данными в вашем приложении, чтобы повысить производительность, а не Redux.

Помимо технических аргументов, описанных в предыдущих ответах, ИМХО есть две важные причины:

  • Инструменты: Redux dev tool - потрясающий инструмент, который делает ваш опыт разработчика / отладки невероятным (машина времени, возможность экспортировать пользовательский сеанс и воспроизводить его в своем локальном окружении...).

  • Удобство переполнения стека: Redux получил более 51000 результатов по переполнению стека, поток 9000.

Другие вопросы по тегам