I am building a site with React and Redux and I have a query about how I should be handling 401 status responses.
Currently when the API reports a 401 HTTP Status it is usually caught in one of my actions and I dispatch:
return dispatch({
type: 'FETCH_MONTHLY_DATA_FAILURE',
error: response.data
});
And the related reducer checks the HTTP status code and I have some Redux middleware that checks for this HTTPStatus state value and reacts accordingly.
Is there a more elegant way I can handle these errors in a general manner? I am using Axios for my HTTP requests.
In response to a client request, the server may return a 401 Unauthorized error. You must correctly catch it, for example, clear the state and redirect to the authorization page. To solve this problem, we wrote a custom Middleware which, in our opinion, is the best solution.
Usually the best approach to error handling with redux is to have an error field in state that is then passed to an error component. The error component doesn't have to just display an error, it could also do side effects with useEffect . How the error is set/unset depends on your application.
redux-saga is a library that aims to make application side effects (i.e. asynchronous things like data fetching and impure things like accessing the browser cache) easier to manage, more efficient to execute, easy to test, and better at handling failures.
You said :
And the related reducer checks the HTTP status code...
Using a middleware is great but the reducer should not check for the http status. It would be outside of its purpose.
From the documentation :
The reducer job is to specify how the application's state changes in response.
Your action-creators should be pure, all the async codes should live somewhere else.
Side effects do not belong in reducers
There are many ways to do it. It all comes down to preferences.
Here are 3 ways to handle HTTP requests in a more elegant way:
Option 1 (the most powerful one) : Generators, Sagas and complex chains of asynchronous operations
redux-saga allows you to do just that. I personally use this middleware to handle my api calls and responses.
The mental model is that a saga is like a separate thread in your application that's solely responsible for side effects. redux-saga is a redux middleware, which means this thread can be started, paused and cancelled from the main application with normal redux actions, it has access to the full redux application state and it can dispatch redux actions as well.
Here are the benefits I get from using this option :
Simplify implementation of use cases like:
In a large multi-user, multi-department blog, if a user had ever clicked on a "subscribe to RSS Feed" button, then the next time the user visits a section that has a dedicated RSS feed, show him/her a suggestion to subscribe to this section's feed.
In an online IDE, if a user has never used a particular feature of an application, but has arrived at a state that the aforementioned feature might potentially be useful, show a help dialog introducing this feature.
In stackoverflow, while the user was responding to a question, the question has been changed by OP so you inform the user that the question has been changed and the answer is potentially no longer valid.
etc.
redux-observable is another option :
Compose and cancel async actions to create side effects and more.
Option 2 : put the intelligence that drives asynchronous operations in your application operations in actions creators
redux-promise or redux-thunk are good exemples.
So far so good. We removed the coupling, separated our the async logic somewhere else and have a clean architecture. However, redux-saga's more advanced feature will simplify complex use cases.
Here is the gist of redux thunk :
Asynchronous middleware like redux-thunk or redux-promise wraps the store's dispatch() method and allows you to dispatch something other than actions, for example, functions or Promises. Any middleware you use can then interpret anything you dispatch, and in turn, can pass actions to the next middleware in the chain. For example, a Promise middleware can intercept Promises and dispatch a pair of begin/end actions asynchronously in response to each Promise.
Option 3 : Managing side effects through Higher order components
Higher-Order Components (HOCs) are JavaScript functions which add functionality to existing component classes. Just as React components let you add functionality to an application, Higher-Order Components let you add functionality to components. You could say they’re components for components.
Not ideal for all use cases !
Exemple : axios, a promise based HTTP client for the browser and node.js
Option 4 : Generators and promises, sans Sagas
Last but not the least, you can still use generators to manage your async control flow, in frontend, without adding redux-thunk dependency, if you do not need some of its advanced features.
Add global response interceptor which dispatches action when error occurs
import store from './store';
// Add a response interceptor
axios.interceptors.response.use(function (response) {
// Do something with response data
return response;
}, function (error) {
// Do something with response error
store.dispatch({
type: 'API_ERROR',
payload: error,
})
return Promise.reject(error);
});
// In you reducers...
reduce(state, action) {
if (action.type === 'API_ERROR' && action.payload.statusCode === 401) {
return { // whatever needed }
}
return state;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With