Reputation: 2828
I am trying to return a promise from dispatch so that I can do something like this in my react component
this.props.dispatch(requestLogin(data))
.then((res) => {
Navigate.toHome()
}).catch((err) => {
this.showErrorMessage()
})
currently I wrapped my fetch to reuse the common things i pass on the server API and to put some logs for debugging. I did it like this:
export const query = (path, opts) => {
// common config and boilerplates here
// e.g add device id to every api request
return fetch(opts.url, reqOpts)
.then((response) => {
console.log('response received')
if (response.ok) {
return response.json()
} else
console.log('response not ok')})
.then((respData) => {
if (respData.status === true) {
console.log('response success')
return respData
} else {
const errObj = respData
errObj.server = true
throw errObj
}
}).catch((err) => {
console.log('error catched')
if (err.server) {
throw err
}
throw { status: false, errors: { error_code: 'ERR_FATAL', error_msg: 'Something went wrong.' }, err }
})
then my action creator is like this:
export function requestLogin (data) {
return function (dispatch) {
const opts = {
method: 'POST',
body: data,
}
return query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
},
(data2) => {
// the thrown error actually returns here
// this returned value goes to the .then of the dispatch
return data2
},
).catch((err) => {
// this is not executed
return err
})
}
}
whats happening is
this.props.dispatch(requestLogin(data))
.then((res) => {
// the error actually goes here
Navigate.toHome()
}
(err) => {
// not here
}).catch((err) => {
// or here
this.showErrorMessage()
})
Upvotes: 5
Views: 2132
Reputation: 180
First, it's important to understand that the second argument you give then(onFulfilled, onRejected)
, which is onRejected
, is another syntax to catch, so because it's written before your catch in the action creator, you get to there when the query function throws an error. that is why the catch block isn't executed. (read about promise's then
).
after you catch your error in onRejected
, it returns a promise, which is not an error anymore(the promise's state is fulfilled and not rejected).
if you want the promise to get to the catch block, you should change your action creator:
return query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
},
(data2) => {
// the thrown error actually returns here
// this returned value goes to the .then of the dispatch
return new Promise((resolve,reject) => {
reject(data2)
}
})
that will return a promise, which is rejected, so it will be caught by the catch block.
also, you can change the
return new Promise((resolve,reject) => {
reject(data2)
}
with
throw 'error'
or
Promise.reject(data2)
let me know if you need any further explanation.
Upvotes: 5
Reputation: 1586
When you doing:
query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
},
(data2) => {
// the thrown error actually returns here
// this returned value goes to the .then of the dispatch
return data2
})
.catch((err) => {
// this is not executed
return err
})
It's actually, you do catch the error of query
function already, then you return data2
. It means you want to return a Promise success (resolve) with data2
. The same thing happen with catch
.
To fix it, you just need to remove the (data2) => {}
and the catch
block.
query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
})
The second way, in case you still want to do something with the error before, you need to return Promise.reject
:
query(Paths.OP_USR_LOGIN, opts)
.then((data) => {
data.TYPE = APP_LOGIN
dispatch(resultData)
})
.catch((err) => {
// you can do something with error, and still return a promise.reject here
console.log('I found an error here', err)
return Promise.reject(err)
})
Upvotes: 3