Damathryx
Damathryx

Reputation: 2828

Redux thunk dispatch does not return error

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

Answers (2)

Adi Elisha
Adi Elisha

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

Dat Tran
Dat Tran

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

Related Questions