|Request/Success/Failure Pattern in Redux (2 Part series)|
|Part 1: Using request/success/failure pattern in Redux to handle async actions|
|Part 2: Simplifying request/success/failure model for async action in Redux for large applications|
A lot of times while making the API calls, we face the challenge; where based on different points of time of API call, we need to show different UI or handle other scenarios in a project. There are a lot of approaches to do the same. However, there is one which is the best and is widely used in many organizations. We will discuss about the same in this article.
When any async action or API call is made, there are mainly 3 states:
- Request State - The async action or API call is in process
- Success State - The async action or API call is successful and gets some data
- Failure State - The async action or API call is errored/failed due to some reasons
Based on these 3 states, we create functions and follow certain conventions etc to achieve the desired result.
Things needed here:
- action functions
- type strings
- reducer function(s)
We pick the main action verb here and append request/success/failure at the end to follow consistent naming convention.
Let's take an example where we will be making an API call to get a list of users. For each of above listed cases, we will create an action and a type each. Corresponding to cases in above list for get list of users, we have now the following actions and types now:
And the corresponding reducer and the initial state will look something like this
When we need to make an api call we will dispatch the request action. It will make isLoading to true and we can use it to show an appropriate message/loader in the screen. As soon as the api call is finished; it will either be in successful or failure state. For each of these, we will dispatch either success or failure which will update the data in the reducer (in data or error variables respectively) as well as make isLoading to false and loaded to true.
The various variables such as isLoading, loaded etc can be now be used in our component for the desired interactions or functionalities.
There are several advantages for this pattern and it closely follows all the good practices recommended in any software development. Few of them are:
- Readability and Maintainability: Since we are following a fixed pattern for naming, code becomes a lot more readable. request/success/failure model communicates properly the state in which API is and reduces mental overhead.
- Code Scalability: This structure is highly scalable. We will see how in our next article where we will reuse this structured format to extend this pattern for multiple API calls and avoid a lot of code repetition.
- Control and Precise Hooks: This pattern also gives us more control. Once implemented, we have hooks at various point in API call to update the UI. Variables like isLoading and loaded give us control over UI whereas actions give control over how to save data in reducer.
The pattern also fits in very nicely which libraries such as redux-thunk or redux-saga.
An example here will demonstrate on how to use the same with redux-saga
and the same can be done easily with thunk as well.
There could be some scenarios where devs might need to reset the data to initial state. In that case, we can add additional action accordingly.
That's it about the pattern. So simple and sleek and yet so powerful!!
The same approach can be extended now for multiple API calls. The only issue is that if one have a lot of api calls, there will be 3 actions, 3 types and 1 reducer per API call. It means that there will be a lot of repetitive code involved and there will be multiple reducers and logic to merge them.
For now, Part 1 of the article ends here. Keep following this space and I will update the link for Part 2 in here shortly!