Dispatching cascading/dependent async requests in Flux/React
Asked Answered
R

1

3

I know this question has been asked more times in different flavours, but I didn’t find the "right" answer yet (maybe there just isn't one), so I’m looking for the "most Flux" one.

Simple example:

  • two components - LoginForm and Information
  • user has to provide his/hers login information, submit the form and only after that he/she has right to "ask" for the information (this should be done automatically after login)
  • Project structure along these lines:

    + actions
    |-- LoginAction
    |-- InfoAction
    + api
    |-- API
    + components
    |-- LoginForm
    |-- Information
    + stores
    |-- LoginStore
    |-- InfoStore
    

Options:

1.

  • LoginForm._onSubmit() calls LoginAction.login()
  • LoginAction.login() calls API.login() with callbacks/promises and then in case of successful login it calls InfoAction.requestInfo()

2.

  • LoginForm._onSubmit() calls API.login()
  • if API.login() is succesful it calls LoginAction.loginSuccess() and:
    1. either InfoAction.requestInfo() which calls API.requestInfo()
    2. or API.requestInfo() which then calls InfoAction.infoSuccess()

3.

  • LoginForm._onSubmit() calls LoginAction.login()
  • InfoStore listens to LOGIN_OK action and it calls the API.requestInfo()
  • API.requestInfo() calls InfoAction.infoSuccess() and that dispatches INFO_OK event with payload of the specific info that is going to be stored in InfoStore

(4.)

calling API/ServiceProvider or ActionCreators from componentWillMount or componentDidMount seems inherently bad. Not really a (good) option, but I’m putting it here for the sake of completeness.

My evaluation:

1. Good in the "old style" of callback/promise based JS, but doesn’t seem to be the Flux way, because we should avoid chaning actions. Just fire-and-forget.

2. Breaks the "Flux diagram" slightly - components speak to API or ServiceProviders and not to ActionCreators directly. I'm not sure about whether this is good or bad. It seems to be "one-way" (good) and avoids circular requires (good). I personally prefer this option (specifically the 2.2. one)

3. I personaly avoid this approach because it would mean Store talking to the API/ServiceProvider which breaks the “Flux diagram”, but again, I don’t know if it’s really bad (maybe it’s just me not being used to the Flux way of doing things). Even @fisherwebdev seems to be ok with this (e.g. https://mcmap.net/q/127586/-where-should-ajax-request-be-made-in-flux-app), but is it really the best approach?

4. Bad, bad, bad!

Question

Which one is "the best" and/or is there any other "most Flux" option to do this?

Rhigolene answered 26/6, 2015 at 15:19 Comment(0)
M
2

I recently watched an informative panel discussion that had, among others, two Facebook developers working on large-scale projects that used React/Flux. What struck me was that they took completely different approaches to the same problem -- and both seem perfectly good.

That said, here's how I'd handle it.

  1. LoginForm.onSubmit calls LoginAction.login.
  2. LoginAction calls API.login and, upon success, the Dispatcher launches an actionType of something like Constants.LOGGED_IN with data of the user_id
  3. A UserStore, listening for Constants.LOGGED_IN makes a call to API.userInfo, passing the user_id that was in the dispatch. (Having a store get information directly from the API was one of the things one of the FB guys said they do routinely, reserving actions for updates and things of that nature.)
  4. UserStore saves info into its current_user and emits a CHANGE
  5. Affected components request an update to UserStore

Now, if you want to get trickier, you can have the store add arguments to its emitmethod, so that the affected components could pick up (a)the nature of what changed and (b)the actual data.

Hopefully, that's food for thought!

Mascia answered 28/6, 2015 at 22:52 Comment(3)
You might be right here, but personally I see this as breaking the "Flux flow diagram" - Broken flux diagram Yes, FB devs seems to be ok with this (and they’re probably authority regarding this matter), but I'd like to have async code in one place only. Second thing is that it could cause a “circular require” - 1. API requires ActionCreator (AC) to call AC.infoReceived() 2. AC requires API to call API.getNextInfo() when Component says so.Rhigolene
Oh and I'm not necessarily talking about "User info" here - just some "general information" (weather report for next day, picture of a day) accessible only after login (behing paywall...). But that's just to clarify my train of thought, it shouldn't make difference in this case.Rhigolene
@TooManyQuestions, what did you end up with?Saudra

© 2022 - 2024 — McMap. All rights reserved.