2014-09-02 2 views
120

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

-ИЛИ-

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

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

+2

Это сообщение может помочь http://www.code-experience.com/async-requests-with-react-js-and-flux-revisited/ –

+0

Для тех, кто оценивает различные реализации шаблона потока, я бы очень рекомендуем взглянуть на Redux https://github.com/rackt/redux. Магазины реализованы как чистые функции, которые принимают текущее состояние и выпускают новую версию этого состояния. Поскольку они являются чистыми функциями, вопрос о том, могут ли они вызывать услуги в сети и хранилище, выводится из ваших рук: они не могут. – plaxdan

ответ

150

Я видел структуру потока реализован в обоих направлениях, и после того, как сделал сам (первоначально происходит с прежним подходом), я считаю, что магазины должны быть тупые получателями данных действий, и что асинхронная обработка писем должны жить в создателях действий. (. Async reads can be handled differently) По моему опыту, это имеет несколько преимуществ, в порядке важности:

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

  2. Все действия отправляются от создателей действия. Если вы обрабатываете асинхронные операции в своих магазинах и хотите, чтобы ваши обработчики действий ваших магазинов были синхронными (и вы должны были получить гарантии однократной отправки потока), ваши магазины должны будут активировать дополнительные действия 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.

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

+15

Я думаю, что происходит из-за вызова веб-ави (action creator vs.магазин) менее важно, чем тот факт, что обратный вызов успеха/ошибки должен создать действие. Таким образом, поток данных всегда: action -> dispatcher -> stores -> views. – fisherwebdev

+1

Было бы лучше или проще протестировать логику запроса в модуле API? Таким образом, ваш модуль API может просто вернуть обещание, которое вы отправляете. Создатель действия просто отправляет на основе разрешения/отказа после отправки начального «ожидающего» действия. Остается вопрос, как компонент прослушивает эти «события», так как я не уверен, что состояние запроса должно отображаться для сохранения состояния. – backdesk

+0

@backdesk Это именно то, что я делаю в приведенном выше примере: отправьте начальное ожидающее действие ('' SOME_ACTION "'), используйте API для запроса ('SomeDataAccessLayer.doSomething (userId)'), который возвращает обещание, и в две функции '.then', отправляют дополнительные действия. Состояние запроса может (более или менее) отображать для сохранения состояния, если приложение должно знать о состоянии состояния. Как эти карты подходят к приложению (например, возможно, каждый комментарий имеет отдельное состояние ошибки, a la Facebook или, возможно, один глобальный компонент ошибки) –

8

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

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

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


Редактировать: Флукс Facebook фактически реализуется в «создателях действий», поэтому они используют интеллектуальные действия. Они также готовят полезную нагрузку с использованием магазинов:

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 - небольшая вариация потока Facebook: https://github.com/spoike/refluxjs Магазины управляют всем доменом «Модель» вашего приложения, а также действиями/диспетчерами, которые только сшивают и склеивают вещи вместе. – Rygu

+1

Итак, я уже об этом подумал и почти ответил на свой вопрос. Я бы добавил его в качестве ответа здесь (для других голосовать), но, по-видимому, я слишком плохой кармой в stackoverflow, чтобы иметь возможность отправить ответ. Итак, вот ссылка: https://groups.google.com/d/msg/reactjs/PpsvVPvhBbc/BZoG-bFeOwoJ – plaxdan

51

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

При ответа на взаимодействие пользователя с UI, я хотел бы сделать вызов асинхронного в методы создания действия.

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

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

+0

Хотя это имеет смысл, любая идея, почему «вызов из магазина лучше работает, когда действие запускается из не-человеческого драйвера»? – SharpCoder

+0

@SharpCoder Я предполагаю, что если у вас есть живой тикер или что-то подобное, вам действительно не нужно запускать действие, и когда вы делаете это из магазина, вам, вероятно, придется писать меньше кода, так как магазин может мгновенно получить доступ к состояние и исправить изменение. – Dodekeract

2

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

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

1

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

Больше explainations здесь: https://stackoverflow.com/a/31388262/82609

3

я приведу аргумент в пользу «неумные» действия.

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

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

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

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

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

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

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

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