Flux best practices: Stores dispatching actions, AJAX calls in Web API Utils?
Asked Answered
G

2

38

enter image description here

I understand that this image has been the ultimate guide of most, if not all, Flux programmers. Having this flow in mind, I have a few questions:

  1. Is it correct/highly advisable to have all of my $.ajax calls inside my Web API Utils?
    • Callbacks call the action creators, passing the data in the process
  2. If I want my Store to make an AJAX call, I do have to call the Action Creator first, right? Is it fundamentally incorrect to call a function in Web API Utils directly from Store?
  3. Is there like a virtual one-sided arrow connecting from Store to Action Creators?
    • I have a lot of operations that do not go through views
  4. What are the Callbacks between Dispatcher and Store?
  5. What's the Web API here? Is this where you'd apply a RESTful API? Is there an example of this somewhere?
  6. Is it okay to have a logic involved (to know which Action to dispatch) in one of my Action Creators? Basically, this action receives the response from my AJAX call. This is a snippet:

    var TransportActions = {
        receiveProxyMessage: function (message, status, xhr) {
            switch (message) {
                case ProxyResponses.AUTHORIZED:
                    AppDispatcher.dispatch({
                        type: ActionTypes.LOGIN_SUCCESS,
                        reply: m
                    });
                    break;
                case ProxyResponses.UNAUTHORIZED:
                    AppDispatcher.dispatch({
                        type: ActionTypes.LOGIN_FAIL,
                        reply: m
                    });
                    break;
                ...
            }
        }
    }
    

I've seen a lot of different answers online, but I am still not sure how I would incorporate all of them in my application. TYIA!

Gripping answered 1/5, 2015 at 11:34 Comment(0)
S
33

Is it correct/highly advisable to have all of my $.ajax calls inside my Web API Utils? Callbacks call the action creators, passing the data in the process.

Yes, you should put all your request into a single entity, i.e. the Web API Utils. They should dispatch the responses so any store can choose to act on them.

I wrote a blogpost a while ago showing one way on how to handle requests http://www.code-experience.com/async-requests-with-react-js-and-flux-revisited/

If I want my Store to make an AJAX call, I do have to call the Action Creator first, right? Is it fundamentally incorrect to call a function in Web API Utils directly from Store?

This is a good question, and as far as I have seen it, everybody does it a little different. Flux (from Facebook) does not provide a full answer.

There are generally two approaches you could take here:

  1. You can make the argument that a Store should not "ask" for any data, but simply digest actions and notify the view. This means that you have to fire "fetch" actions within the components if a store are empty. This means that you will have to check on every data-listening view if it has to fetch data. This can lead to code duplication, if multiple views listen to the same Store.

  2. The Stores are "smart" in the sense that if they get asked for data, they check if they actually have state to deliver. If they do not, they tell the API Utils to fetch data and return a pending state to the views.

    Please note that this "tell the API to fetch data" is NOT a callback based operation, but a "fire and forget" one. The API will dispatch actions once the request returns.

I prefer option 2 to option 1, and I've heard Bill Fisher from the Facebook team say that they do it like this as well. (see comments somewhere in the blogpost above)

so No it is not fundamentally wrong to call the Api directly from the Store in my opinion.

Is there like a virtual one-sided arrow connecting from Store to Action Creators?

Depending on your Flux implementation there might very well be.

What are the Callbacks between Dispatcher and Store?

They are the only functions that can actually change the state in a store! each Store registers a callback with the Dispatcher. All the callbacks get invoked whenever a action is dispatched. Each callback decides if it has to mutate the store given the action type. Some Flux libraries try to hide this implementation detail from you.

What's the Web API here? Is this where you'd apply a RESTful API? Is there an example of this somewhere?

I think in the picture the Web API rectangle represents the actual server, the API Utils are the ones that make calls to the server (i.e. $.ajax or superagent). It ist most likely a RESTful API serving JSONs.

General advice:

Flux is a quite loose concept, and exact implementations change from team to team. I noticed that Facebook has changed some approaches here and there over time as well. The exact cycle is not strictly defined. There are some quite "fixed" things though:

  1. There is a Dispatcher that dispatches all actions to all stores and permits only one action at the time to prevent event-chain hell.
  2. Stores are action receivers, and all state must be changed through actions.
  3. actions are "fire and forget" (no callbacks!)
  4. Views receive state from the store and fire actions

Other things are done differently from implementation to implementation

Sama answered 1/5, 2015 at 12:56 Comment(5)
Wow, that was your article? I totally read that one a few times already! However, I felt intimidated with the "pending requests" idea. I wasn't sure how to apply it.Gripping
Don't feel initimidated by the pending requests stuff. It has nothing to do with flux at all. You can leave that away completely if you like. The big takeaway of the blogpost is that you do not sprinke async callbacks all over your app that are hard to reason about. You make the request, and dispatch the the response to the rest of the app in one single place.Sama
I understand. I might have to implement that soon in my app. By the way, I have updated my question with a #6 follow-up (I'm not sure if that's allowed here.) When you mentioned that the stores are "smart", should they be too smart that they have all the logic in the app? Should all of the other elements (Dispatcher, View, Action Creator, or even the Web API, I guess) be just dumb and accept/pass actions/data? Because I'm extremely curious on where I'd filter the messages returned by the Web API Utils.Gripping
You might want to extract this into a new question. It's a good one, and there are multiple strategies for handling filtering and other mutation of state. I will for sure provide an answer to it...Sama
Thanks a lot for the answer and blogpost! It clarified a lot of things in Flux architecture.Moly
A
5
  1. Is it correct/highly advisable to have all of my $.ajax calls inside my Web API Utils? Callbacks call the action creators, passing the data in the process.

Absolutely.

  1. If I want my Store to make an AJAX call, I do have to call the Action Creator first, right? Is it fundamentally incorrect to call a function in Web API Utils directly from Store?

First, ask yourself why your store needs to do an API call. The only reason I can think of is that you want to cache the received data in the stores (I do this).

In the most simple Flux implementations, all Actions are created from only the View and Server. For example, a user visits a "Profile" view, the view calls a profileRequest action creator, the ApiUtils is called, some data comes in, a ServerAction is created, the ProfileStore updates itself and the ProfileView does accordingly.

With caching: the ProfileView ask the ProfileStore for some profile, the store doesn't have it, so returns an empty object with state 'loading', and calls ApiUtils to fetch that profile (and forgets about it). When the call finishes, a ServerAction will be created, the ProfileStore will update itself, etc. This works fine. You could also call and ActionCreator from the store, but I don't see the benefit.

MartyJS does something similar. Some flux implementations do the same with promises.

I think the important part is: when data comes back into the system, a ServerActionCreator is called with the new data. This then flows back into the stores.

I believe stores should only query data, all state-changing actions (updating stuff) should be user-initiated (come from views). Engineers from Facebook wrote about this here: https://news.ycombinator.com/item?id=7719957

  1. Is there like a virtual one-sided arrow connecting from Store to Action Creators?

If you want your stores to be smart: yes. If you want your app to be simple: no, go through Views.

  1. What are the Callbacks between Dispatcher and Store?

These are the dispatch handlers you find in stores. The dispatcher fires an action, stores listen to this fire event and do something with the action/payload.

  1. What's the Web API here? Is this where you'd apply a RESTful API? Is there an example of this somewhere?

This is where your ajax calls go. Typically this will mean some REST API, but could als be websockets or whatever. I've always loves this tutorial: http://fancypixel.github.io/blog/2015/01/29/react-plus-flux-backed-by-rails-api-part-2/

Disclaimers: these are my interpretations of Flux. Flux itself doesn't really solve fetching data, that's why they've come up with Relay and GraphQL at FB

Audley answered 1/5, 2015 at 12:16 Comment(3)
"You could also call and ActionCreator from the store, but I don't see the benefit." -- I actually have some kind of chain of operations, so I'd be forced to call an ActionCreator (automatically) from my Store. What's your take on this?Gripping
I think it's fine, I think I started out this way, but created circular dependencies at one point. MartyJS solved this with 'queries', special action creators for querying from stores: martyjs.org/guides/queries/index.htmlAudley
"First, ask yourself why your store needs to do an API call" -> It depends on where you want to put the logic. Some people think that stores should be dump containers of data from views (user/server), others think that views should be dump displayers of smart stores. No one agrees on where to put the logic. Fat "models" vs fat "views". The "controller" is thin.Limicolous

© 2022 - 2024 — McMap. All rights reserved.