Redux. Ajax calls from inside components. Bad code smell or avoid overengineering?

(Joris Mans) #1

This comes from a disussion we recently had on Github (the current implementation uses REDUX btw).

The question is: should every interaction with your server go through the action -> reducer -> update application state -> update component properties cycle, or are there cases where we can shortcut this and do an ajax call from within a component which upon returning (e.g. using a promise) change component state which will trigger a GUI update?

One of the arguments against using ajax:

The approach isn’t scalable for several reasons. If you have a thousand different components, you can’t reasonably be making a thousand different requests (you’ll need to implement batching of some sort). If you have the same the same component multiple times, you’ll want them to share a single value in memory (to avoid duplicate requests, or for consistency if the data is mutable, etc). Also more difficult to subscribe to updates in case the underlying resource (on the server) changes (you would need to hold open a connection for every component, instead of a single shared connection). Sideways data loading makes it more difficult for developers to reason about your application, since components are no longer a pure function of props+state (they are reading some outside data source). The list goes on, but I’ll truncate it there in the interest of time - the bottom line is that flux exists for a reason and it’s a bad style for a component to make an ajax request directly.

And my counter-argument pro:

Of course I am not advocating bypassing state + props entirely in favour of doing Ajax calls.
The issue you can have when going into the other extreme is that your state object is littered with all kinds of variables that only make sense for 1 component class in your app, and if you have hundreds of those you’ll end up with a state containing hundreds of properties that have a very small scope or even life time (imagine rendering a popup that only shows some useful information after registering an account, do you really want an application state property for the info inside that popup polluting your code when it is used only one time in the entire lifecycle of your app, in 1 popup?), and will spend 99.9% of their time simply being == null

I am not saying I am right and he is wrong, or vice versa, but I would like to have more opinions about this.

My main issue is that I want to keep my state “clean”. The state for me is the stuff that matters through the majority of the app, and not some strings and bools that are only shown in one component that only exists in a very short and specific time.

What are your best practices and recommendations on this matter?

(Tran Trung Tin) #2

I’m a newbie too but IMHO, both of you are correct in its own way. In my case, like you, I want to keep my state clean, so I put all of request call and action creator into same file, this way I can use higher order function to batch multiple request (here a thoughtful read, then with small action I just import the request function and apply change to component state. Many of my component not use props directly but put data into state base on props, so there shouldn’t be problem with single source of truth. Yes there are problem with sideway data, but I don’t think it a big issue here. If there are many component share data then of course that data must be in app state.

(Vlad Churakov) #3

I’ve come across the same questions many times. As it’s been already said, being connected to the redux global state, components are allowed to have their own local states (please kick me if I’m wrong). Here are my 20 cents. The state has to be shared only if the shared piece of the state is reused by either any other component
OR the same component being mounted/unmounted many times uses the same data.

Here’s my check-list:

  • should the state remain between mounting/unmounting a component?

  • should be used by more than one component?
    If either yes, should be kept in the redux state.

  • doesn’t it matter if the state is lost when the component is unmounted?

  • is none of the components used that part of the state?
    if either yes, should be kept in the form of a local state in a container components