I am working on a React application which uses redux-axios-middleware
to do XHR requests. The way it is setup is with a client in the index.js
like so:
const client = axios.create({ //all axios can be used, shown in axios documentation
baseURL:'https://api.vktest.xxx/api',
responseType: 'json',
validateStatus: function (status) {
return status >= 200 && status < 300
}
});
const axiosMiddle = axiosMiddleware(client)
export const store = createStore(rootReducer, composeEnhancers(applyMiddleware(thunk, axiosMiddle)))
From my component I am then calling my action like so:
store.dispatch(loginAction(credentials))
This is the action:
import { LOGIN } from './types'
export function loginAction(credentials) {
return dispatch => {
return dispatch(doLogin(credentials) ).then(
response => {
dispatch({type: 'LOGIN_SUCCESS', response})
},
error => {
dispatch({type: 'LOGIN_FAIL', error})
throw error
}
)
}
}
function doLogin(credentials) {
return {
type: LOGIN,
payload: {
request: {
url: '/login/',
method: 'POST',
data: {
username: credentials.username,
password: credentials.password
}
}
}
}
}
It dispatches the doLogin function which is captured by axios-middleware to do the XHR call. After the call the axios promise contains either the type LOGIN_SUCCESS
or LOGIN_FAIL
. Axios automatically dispatches these types and the reducers can act on them. So far so good.
However (and I am trying to be as clear as possible), when the axios request fails, the axios promise is rejected and the LOGIN_FAIL
type is dispatched. Since that promise is resolved the .then(..).catch(..)
block is alway's calling the .then
. I cannot seem to handle the axios error with doing something ugly in the .then
block which handles the dispatch callback and not the axios callback.
To clearify the following is happening:
store.dispatch -> action -> doLogin -> axios -> reducer -> back to action dispatch.
I want to handle XHR errors between the axios and reducer step but when I do:
import { LOGIN } from './types'
export function loginAction(credentials) {
return dispatch => {
return dispatch(doLogin(credentials).then(
response => {
dispatch({type: 'LOGIN_SUCCESS', response})
},
error => {
dispatch({type: 'LOGIN_FAIL', error})
throw error
}
))
}
}
function doLogin(credentials) {
return {
type: LOGIN,
payload: {
request: {
url: '/login/',
method: 'POST',
data: {
username: credentials.username,
password: credentials.password
}
}
}
}
}
I get the following error:
Uncaught TypeError: doLogin(...).then is not a function
at authentication.js:6
The reason I want to fix this is because the current setup dispatches the following:
As seen in the image both the LOGIN_FAIL
(axios) and the LOGIN_SUCCESS
(dispatch) are being called. I want to be able to handle the axios error myself since I want to be able to for example give the user feedback of a failed login attempt. Somehow I am not able to figure out how.
Can someone help me?
I think I know what you mean.
You can change that behavior by setting returnRejectedPromiseOnError in middleware config.
Note that promise is returned only to chain actions. If you set this option you will have to always apply catch
callback or you will be getting unhandled rejection when calling Promise
errors. And this might be causing some issues when handled in components, because these callbacks may be fired when component is already unmounted.
Im my code I try to avoid then
as much as possible to avoid these side effects but when I have to I do it like:
fetchSomething.then(action => {
if(action.type.endsWith('SUCCESS')) {
....
}
})
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