How i learned how not to Flux.

So let’s start at the beginning. I was starting my first application written purely with flux and react. Prior to starting work on the application i had messed around with writing a simple implementation of the flux architecture. It was early November 2014, just about the time when everyone started to write their own flux based framework. I remember looking around at what other people were doing, watching the few talks and reading the few articles i could find, and i thought to myself “pff, who the hell needs action creators anyway? I’ll just call my API handlers from the stores themselves which will then create the success and fail actions.” Boy was i wrong.

What happens when you omit action creators from your flux architecture is that your data handling logic gets scattered all over your stores and components. Of course i didn’t realize this until my control flow became rather complex. I had to scan a QR code, wait for the response, issue an API request, wait for the response, and then dispatch a changed event on the store in question. No problem, i’ll put this logic in the store. It makes sense, right? everyone who wanted to interact with my store had to go through that same process. Worked fantastically, until i needed my component to change according to the response from the API. I thought “I’ll just emit a change event with my store and have the payload be a type string containing success or error!” Nope, that would make my components impure, they would no longer be a function of props and state. “Hmm, maybe if i just pass around request ids?” Wrong again, well not completely, but they shouldn’t be passed to the store. My component might be the only one interested in that particular request in that specific flow, another component might need to know about another request in that flow or a completely different flow that also interacts with that store, and then i’m screwed. Not to mention handling multiple requests involving the same store. It would never work.

The problem is that what we’re looking for isn’t state associated with the store or the component. It’s not even state, it’s a state transition. We only want to react when the action fails or succeeds and that’s it.

What you need to be able to handle this scenario, or any scenario where your view is interested in a response from a request somewhere deeply embedded in the control flow, is to put that control flow inside an action creator. This way you’ll have one place where you control the flow of mapping interaction to actions and data requests, one place where you store information contained in the results from those data requests, and one place where you have all the logic on how to display the information kept in the stores.

Couldn’t we just return a promise from our action creators? Inversion of control and what not? Sure, i guess we could, but then we start mixing presentation logic and data flow in our components, which would make our components harder to test. Handling promises in a component just doesn’t seem right, it’s not very React-like, it should not be the components responsibility to know how to deal with asynchronous data requests.

So how do you actually track these requests?

So what’s the deal with these requests ids? Well i’ll tell you. The interaction with your component might trigger an HTTP request to post/get/put/delete data, and you typically want to know if it was successful or if it failed, so you can display some kind of feedback to the user. Let’s say i have an ArticleStore and the user posts an article. This is where the RequestStore comes in. The request store is just a list of all request our components are currently interested in. For any particular request we have 2 possible outcomes, success or fail. So we simply create a RequestActionCreator that has a method for making a request and a request id, and a method for tracking that request. All it needs to do is dispatch an action to put the request in the RequestStore and when the request finishes it dispatches the appropriate action to update the request in the RequestStore with the response details. Why is this handy? Because then we can make a RequestTracker component that listens to the RequestStore for changes. In the store change handler, we can check the store for state transitions involving the request id we generated in our action creator. Here’s what a component that needs to listen for a request might look like (i’ve been using CoffeeScript for 3 years so my JavaScript might be a bit rusty, bear with me).

Code example for using the request tracker

Pretty cool right? All we need to make this work is to return the requestId from the action creator. Now we have complete control over which request to track, and nobody but the component responsible for the request will be bothered with it. The component doesn’t need to know about sync/async, promises, generators or whatever trick you use to handle async actions. The ArticleStore doesn’t care anymore either. If we need to reuse the same flow, we can either just call the method on the ActionCreator or make a new method that tracks a different request in the flow.

But what about the RequestStore? It will have every single request that was ever tracked during the current session of our application. We’ll need to get rid of the request somehow. Fortunately, we don’t render the RequestTracker anymore when we know the status of the request, so we can just clear out the request in question from the RequestStore on componentWillUnmount in the RequestTracker component.

Here’s the complete (untested) code for the RequestTracker:

The code for the RequestTracker

You could even expand this to include file upload progress, or whatever you need, since it’s all contained nicely within your RequestActionCreator, the RequestStore and the RequestTracker component. You could even make a cool little component to show all current tracked requests and their status at any given time in the application lifecycle.

That’s all there is to it. Now go properly track some requests, and i’ll see you next time!