【问题标题】:In Flux what is responsible for direct talking to API在 Flux 中负责直接与 API 对话的是什么
【发布时间】:2015-04-06 13:08:34
【问题描述】:

我正在努力学习 Flux,并观看并阅读了这些令人惊叹的资源

我仍然不明白Flux 架构的哪个部分(ActionDispatcherStore)负责与 API 通信,前提是我的 API 是异步的,并且能够推送数据- 即当有新数据可用时,我会收到一个事件。

此图像表明 Action 正在与 API 通信,但多个代码示例显示 Action 仅触发 Dispatcher..

【问题讨论】:

    标签: javascript facebook reactjs reactjs-flux


    【解决方案1】:

    如果您将 Action 的作用视为通知 Store 更新的状态数据,那么实际获取新数据的 API 调用应该在调用 Action 之前(例如,在组件的事件处理程序中)进行似乎是明智的。但是,您可能不希望 API 相关的逻辑分散在您的视图中。为了避免这种情况,有时在上图中的 View 和 Action 之间引入了一个 ActionCreators 模块。

    通过调用适当的动作来进行 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 内。添加待办事项后,TodoActions.add() 可以通过 OPTIMISTIC_TODO_ADD 触发乐观 UI 更新,该更新将插入到 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")
      

      根据我的经验,我首先介绍的解决方案提供了一种对 UI 进行乐观更新、处理错误和显示加载指示的好方法。

      【讨论】:

        【解决方案3】:

        Reto Schläpfer 非常清晰地解释了他如何解决同样的问题:

        更聪明的方法是直接从 Action Creator 调用 Web Api,然后 >让 Api 以请求结果作为有效负载发送事件。 Store(s) >可以选择监听这些请求动作并相应地改变它们的状态。

        在我展示一些更新的代码 sn-ps 之前,让我解释一下为什么这是优越的:

        所有状态更改都应该只有一个渠道:调度程序。这 > 使调试变得容易,因为它只需要 >dispatcher 中的单个 console.log 来观察每个状态更改触发器。

        异步执行的回调不应泄漏到 Store。其后果难以完全预见。这会导致难以捉摸的错误。商店 > 应该只执行同步代码。否则它们太难理解了。

        避免触发其他操作的操作使您的应用变得简单。我们使用来自 Facebook 的最新 >Dispatcher 实现,它在 >dispatching 时不允许新的 dispatch。它迫使你做正确的事。

        全文: http://www.code-experience.com/the-code-experience/

        【讨论】:

          猜你喜欢
          • 2014-07-12
          • 1970-01-01
          • 2012-05-14
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多