2015-02-06 4 views
2

Я пытаюсь научиться Flux, и наблюдая и читать эти удивительные ресурсыВ Flux, что несет ответственность за прямой Разговаривая с API

Я до сих пор не понимаю, какая часть архитектуры Flux (Action, Dispatcher или Store) отвечает за общение с API, при условии, что мой API является асинхронным и способен передавать данные - то есть я получаю событие, когда новые данные становятся доступными.

Это изображение показывает, что Action разговаривает с API, однако многочисленные примеры кода показывают, что Action только запуск Dispatcher .. Flux architecture

ответ

2

Если посмотреть на роль действий, как информирование Магазины обновленных данных о состоянии, его Кажется разумным, что вызовы API, которые фактически получают новые данные, должны появиться перед вызовом Action (например, в обработчиках событий компонента). Однако вам может не понадобиться логика, связанная с API, разбросанная по всем вашим представлениям. Чтобы этого избежать, модуль ActionCreators иногда вводится между View и Action в приведенной выше диаграмме.

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

user clicks login -> 
click handler calls ActionCreator.login(), which makes the API call -> 
result is passed to Stores by calling Actions -> 
Stores update their state accordingly 

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

2

После пары месяцев работы с React + Flux я столкнулся с тем же вопросом и попробовал несколько разных подходов. Я пришел к выводу, что лучший способ это иметь дело с действиями обновления данных, как локальных и удаленных:

# COMPONENT 
TodoItems = React.createClass 
    componentDidMount: -> 
     TodoStore.addListener("CHANGE", @_onChange) 
    _onChange: -> 
     @setState { 
      todos: TodoStore.get() 

    _onKeyDown: (event) -> 
     if event.keyCode == ENTER_KEY_CODE 
      content = event.target.value.trim() 
      TodoActions.add(content) 

    render: -> 
     React.DOM.textarea {onKeyDown: @_onKeyDown} 


# ACTIONS 
class TodoActions 
    @add: (content) -> 
     Dispatcher.handleAction({type: "OPTIMISTIC_TODO_ADD", todo: {content: content}}) 
     APICall.addTodo({content: content}) 

# STORE 
class TodoStore extends EventEmitter 
    constructor: -> 
     @todos = [] # this is a nice way of retrieving from localStore 
     @dispatchToken = @registerToDispatcher() 

    get: -> 
     return @todos 

    registerToDispatcher: -> 
     Dispatcher.register (payload) => 
      type = payload.type 
      todo = payload.todo 
      response = payload.response 

      switch type 
       when "OPTIMISTIC_TODO_ADD" 
        @todos.push(todo) 
        @emit("CHANGE") 

       when "TODO_ADD" 
        # act according to server response 
        @emit("CHANGE") # or whatever you like 


#### APICall 
class APICall # what can be called an 'action creator' 
    @addTodo: (todo) -> 
     response = http.post(todo) # I guess you get the idea 
     Dispatcher.handleAction({type: "TODO_ADD", response: response}) 

Как вы можете видеть, «сок» находится в пределах TodoActions. Когда добавляется todo, TodoActions.add() может инициировать оптимистичное обновление пользовательского интерфейса через OPTIMISTIC_TODO_ADD, который будет вставляться в TodoStore.todos. Параллельно он знает, что это должно быть сообщено серверу. Внешняя сущность - ApiCall (которая может считаться создателем действия) - несет ответственность за удаленную часть этого действия, и когда вы получаете ответ, он следует своему нормальному курсу TodoStore, который может действовать соответствующим образом.

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

Позволяет себе это:

class TodoActions 
    # TodoActions is `dumb`, only passes data and action types to Dispatcher 
    @add: (content) -> 
     Dispatcher.handleAction({type: "TODO_ADD", todo: {content: content}}) 
     # APICall.addTodo({content: content}) 

class TodoStore extends EventEmitter 
    # ... 
    registerToDispatcher: -> 
     # ... 
     when "TODO_ADD" 
      @todos.push(todo) 
      # now the store has to push it to the server 
      # which means that it will have to call actions or the API directly = BAD 
      # lest assume: 
      APICall.addTodo({content: content}) 

      # it also generates some uncertainty about the nature of the event emit: 
      # this change can guarantee that data was persisted within the server. 
      @emit("CHANGE") 

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

0

Рето Schläpfer объясняет, как он приближается к этой же проблеме с большой ясностью:

Умнее путем для вызова Web Api непосредственно от Творца действий, а затем> сделать АНИ диспетчерским событие с результатом запроса как полезная нагрузка. Store (s)> может выбрать прослушивание этих запросов и изменить их состояние соответственно.

Перед тем, как показать некоторые обновленные фрагменты кода, позвольте мне объяснить, почему это выше:

Там должен быть только один канал для всех изменений состояния: Диспетчер. Это> упрощает отладку, потому что для диспетчера диспетчера нужно только один console.log наблюдать каждый триггер изменения состояния.

Асинхронно выполненные обратные вызовы не должны течь в магазины. Последствия> этого просто трудно полностью предвидеть. Это приводит к неуловимым ошибкам. Магазины> должны выполнять только синхронный код. В противном случае их слишком сложно понять.

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

Полный текст статьи: http://www.code-experience.com/the-code-experience/

Смежные вопросы