Должны ли магазины потоков или действия (или оба) касаться внешних служб?

126

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

-OR -

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

Мне кажется, что он должен быть тем или иным (а не сочетанием обоих). Если да, то почему один предпочтительный/рекомендуемый по сравнению с другим?

  • 2
    Этот пост может помочь code-experience.com/…
  • 0
    Для тех, кто оценивает различные реализации шаблона потока, я настоятельно рекомендую взглянуть на Redux. Github.com/rackt/redux Хранилища реализованы как чистые функции, которые принимают текущее состояние и генерируют новую версию этого состояния. Поскольку они являются чистыми функциями, вопрос о том, могут ли они вызывать сетевые службы и службы хранения, вынимается из ваших рук: они не могут.
Теги:
reactjs-flux

6 ответов

150
Лучший ответ

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

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

  • Все действия отправляются от создателей действия. Если вы обрабатываете асинхронные операции в своих магазинах и хотите, чтобы обработчики действий ваших магазинов были синхронными (и вам нужно, чтобы получить flux single-dispatch), ваши магазины должны будут активировать дополнительные действия SUCCESS и FAIL в ответ на асинхронную обработку. Вместо этого эти рассылки в создателях действий помогают разделить задания создателей действия и магазинов; кроме того, вам не нужно прокладывать путь через логику магазина, чтобы выяснить, куда отправляются действия. Типичное асинхронное действие в этом случае может выглядеть примерно так (измените синтаксис вызовов dispatch на основе вкуса потока, который вы используете):

    someActionCreator: function(userId) {
      // Dispatch an action now so that stores that want
      // to optimistically update their state can do so.
      dispatch("SOME_ACTION", {userId: userId});
    
      // This example uses promises, but you can use Node-style
      // callbacks or whatever you want for error handling.
      SomeDataAccessLayer.doSomething(userId)
      .then(function(newData) {
        // Stores that optimistically updated may not do anything
        // with a "SUCCESS" action, but you might e.g. stop showing
        // a loading indicator, etc.
        dispatch("SOME_ACTION_SUCCESS", {userId: userId, newData: newData});
      }, function(error) {
        // Stores can roll back by watching for the error case.
        dispatch("SOME_ACTION_FAIL", {userId: userId, error: error});
      });
    }
    

    Логика, которая в противном случае может быть дублирована в разных действиях, должна быть извлечена в отдельный модуль; в этом примере этот модуль будет SomeDataAccessLayer, который обрабатывает фактический запрос Ajax.

  • Вам нужно меньше создателей действий. Это не так много, но приятно иметь. Как упоминалось в № 2, если в ваших магазинах имеется обработка синхронных действий (и они должны), вам нужно будет активировать дополнительные действия для обработки результатов асинхронных операций. Выполнение отправлений в создателях действий означает, что один создатель действия может отправлять все три типа действий, обрабатывая результат самого асинхронного доступа к данным.

  • 15
    Я думаю, что исходящий вызов веб-API (создатель действия или хранилище) менее важен, чем тот факт, что обратный вызов успеха / ошибки должен создать действие. Таким образом, поток данных всегда будет таким: action -> dispatcher -> stores -> views.
  • 1
    Будет ли лучше / проще проверить фактическую логику запроса в модуле API? Таким образом, ваш модуль API может просто вернуть обещание, от которого вы отправляете. Создатель действия просто отправляет сообщение на основе разрешения / сбоя после отправки начального «ожидающего» действия. Остается вопрос, как компонент слушает эти «события», так как я не уверен, что состояние запроса должно отображаться в состояние хранения.
Показать ещё 2 комментария
53

Я написал этот вопрос разработчикам в Facebook, и я получил от Билла Фишера ответ:

При ответе на взаимодействие пользователя с пользовательским интерфейсом я делаю асинхронный вызов в методах создания действия.

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

Важно создать действие в обратном вызове ошибки/успеха, поэтому данные всегда возникают с действиями

  • 0
    Хотя это имеет смысл, есть ли идея, почему a call from store works better when action triggers from non-human driver ?
  • 0
    @ SharpCoder Я думаю, если у вас есть тикер в реальном времени или что-то подобное, вам не нужно запускать действие, а когда вы делаете это из магазина, вам, вероятно, придется писать меньше кода, так как магазин может мгновенно получить доступ к состоянию. & испустить изменение.
8

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

В каждой реализации Flux я видел, что Actions - это в основном строки событий, которые превращаются в объекты, например, традиционно у вас будет событие с именем "anchor: clicked", но в Flux оно будет определено как AnchorActions.Clicked. Они даже настолько "тупые", что большинство реализаций имеют отдельные объекты Dispatcher, чтобы фактически отправлять события в прослушиваемые магазины.

Лично мне нравится реализация Flux Flux, где нет отдельных объектов Dispatcher, а объекты Action сами отправляют.


edit: Facebook Flux на самом деле выбирает "создателей действий", поэтому они используют интеллектуальные действия. Они также готовят полезную нагрузку, используя магазины:

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/actions/ChatMessageActionCreators.js#L27 (строки 27 и 28)

Обратный вызов при завершении затем запускает новое действие на этот раз с извлеченными данными в качестве полезной нагрузки:

https://github.com/facebook/flux/blob/19a24975462234ddc583ad740354e115c20b881d/examples/flux-chat/js/utils/ChatWebAPIUtils.js#L51

Итак, я думаю, что лучшее решение.

  • 0
    Что это за реализация Reflux? Я не слышал об этом. Ваш ответ интересен. Вы имеете в виду, что реализация вашего магазина должна иметь логику для выполнения вызовов API и так далее? Я думал, что магазины должны просто получать данные и просто обновлять свои значения. Они фильтруют определенные действия и обновляют некоторые атрибуты своих магазинов.
  • 0
    Reflux - это небольшое изменение Flux от Facebook: github.com/spoike/refluxjs Магазины управляют целым доменом «Модели» вашего приложения, а не действиями и диспетчерами, которые только склеивают и склеивают вещи.
Показать ещё 3 комментария
3

Я предоставлю аргумент в пользу "немых" действий.

Соблюдая ответственность за сбор данных просмотра в своих действиях, вы связываете свои действия с требованиями к данным ваших просмотров.

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

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

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

Цель магазина - предоставить данные для просмотра. Название "Действие" подсказывает мне, что его цель - описать изменение моего Приложения.

Предположим, вам нужно добавить виджет к существующему представлению панели мониторинга, в котором будут показаны некоторые причудливые новые агрегированные данные, которые только что развернули ваши бэкэнд-команды.

С помощью "умных" действий вам может потребоваться изменить действие "Обновить-панель" Action, чтобы использовать новый API. Однако "Обновление панели инструментов" в абстрактном смысле не изменилось. Требования к данным ваших просмотров - это то, что изменилось.

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

2

gaeron flux-react-router-demo имеет приятное изменение полезности для "правильного" подхода.

ActionCreator генерирует обещание от внешней службы API, а затем передает обещание и три константы действий функции dispatchAsync в прокси-сервере/расширенном диспетчере. dispatchAsync всегда будет отправлять первое действие, например. "GET_EXTERNAL_DATA", и как только обещание вернется, он отправит "GET_EXTERNAL_DATA_SUCCESS" или "GET_EXTERNAL_DATA_ERROR".

1

Если вы хотите, чтобы в один прекрасный день была создана среда разработки, сопоставимая с тем, что вы видите в знаменитом видео Bret Victor "Изобретая по принципу" , используйте немые магазины, которые являются просто проекцией действий/событий внутри структуры данных без какого-либо побочного эффекта. Это также помогло бы, если бы ваши магазины фактически были частью одной и той же глобальной неизменяемой структуры данных, например, в Redux.

Больше объяснений здесь: https://stackoverflow.com/questions/9448215/tools-to-support-live-coding-as-in-bret-victors-inventing-on-principle-talk

Ещё вопросы

Сообщество Overcoder
Наверх
Меню