Flux: How to make an action wait for a store?
Asked Answered
E

1

5

I'm tying myself in knots with a React problem which I'm sure can't be as difficult as it seems to me right now.

I'm building a single page app against a RESTful server API that returns resources, together with links that describe what can be done with that resource. And I'm trying to ensure that my client's ajax calls only use URLs retrieved from the server in this way. So, for example, my LoggedInSessionStore contains the URL that allows me to fetch the list of all public documents, say.

The problem I have is how to manage the dependencies between actions and stores. For example, when the action to fetch all public documents fires, it needs to get its URL from the LoggedInSessionStore. But that store may not yet have been populated yet; so the action must not fire until a previous action (fetch the login session) has completed.

So, I want an action that can fetch server data using a URL that is stored in a store. What is the accepted way to ensure that the action cannot fire until that store has been populated?

Egyptology answered 22/5, 2015 at 19:32 Comment(0)
D
3

TL;DR Don't store your URLs in your Stores. Let your actions handle API calls.

In general when using Flux your actions should not know about your stores. Data in a Flux application is meant to flow in one direction:

Components --> Actions --> Dispatcher --> Stores --> Components

Your React components create actions, which are then dispatched by the Dispatcher to your stores. Stores will be notified of the actions via their registered callback and will update themselves accordingly. Components will listen for stores to update themselves and they will update their own state accordingly. Thus the circle is completed.

The point being: Actions should not depend on stores

What I would suggest is that you move all your API logic into actions. This includes the URLs for your API. This is a fairly common pattern in Flux applications:

  1. A component triggers a fetch action on componentDidMount. Displays loading spinner since it does not yet have the data it needs to render.
  2. The fetch action makes an AJAX call to fetch data from the server.
  3. When the data comes back from the server, the action dispatches it as a payload
  4. A store sees the payload and sets its internal state based on the fetched data
  5. The component sees that the store has been updated, and updates its own state accordingly. This causes it to render the app instead of just a loading spinner.

An alternative option is have your fetch logic inside your stores, including the AJAX request code. I find the former easier to reason about (stores know nothing, they just react to data when its available) but it's up to you how you want to implement it. Just make sure that the API fetching logic is in one place only, not split between Actions and Stores.

This thread may also be helpful: Should flux stores, or actions (or both) touch external services?

Debus answered 22/5, 2015 at 20:5 Comment(2)
Thanks for your answer @ian. My code is structured exactly as you recommend, and I think that's part of my problem. The other part of the problem is that I'm trying to follow HATEOAS principles: the URL needed by each action comes from the server, from the result of an earlier API call. So every action except the first must wait for the URL to arrive back from the server in a previous payload (and then presumably be saved in a Store). So my question is: is React/Flux incompatible with HATEOAS?Egyptology
That's a good question, but unfortunately I can't help you there. I've never tried applying HATEOAS principles to a Flux applicationDebus

© 2022 - 2024 — McMap. All rights reserved.