1

I think I understand where the error is occurring but I am able to work out the correct handling flow for a Promise returned from fetch()

My Messages reducer module: -

import { fetchMessages } from '_helpers/api'
import { Map, fromJS } from 'immutable'

const FETCHING_MESSAGES = 'FETCHING_MESSAGES'
const FETCHING_MESSAGES_FAILURE = 'FETCHING_MESSAGES_FAILURE'
const FETCHING_MESSAGES_SUCCESS = 'FETCHING_MESSAGES_SUCCESS'
const ADD_MESSAGES = 'ADD_MESSAGES'

const ERROR_MESSAGE = 'There has been an error'

export const fetchAndHandleMessages = () => {

  return (dispatch, getState) => {

    dispatch(fetchingMessages())

    fetchMessages()
      .then((r) => {
        if (!r.ok) {
          dispatch(fetchingMessagesFailure(ERROR_MESSAGE))
        }else{
          return r.json()
        }
      })
      .then((b) => {
        dispatch(fetchingMessagesSuccess(b))
      })
      .catch(() => {
        dispatch(fetchingMessagesFailure(ERROR_MESSAGE))
      })
  }
}

function fetchingMessagesSuccess(messages) {
  return {
    type: FETCHING_MESSAGES_SUCCESS,
    messages,
    lastUpdated: Date.now(),
  }
}

function fetchingMessagesFailure(errMsg) {
  return {
    type: FETCHING_MESSAGES_FAILURE,
    error: errMsg
  }
}

const fetchingMessages = () => {
  return {
    type: FETCHING_MESSAGES,
  }
}

const initialState = fromJS({
  messages: [],
  isFetching: true,
  error: '',
})

export const messagesReducer = (state = initialState, action) => {
  switch (action.type) {
    case FETCHING_MESSAGES :
      return state.merge({
        isFetching: true,
      })
    case FETCHING_MESSAGES_SUCCESS :
      return state.merge({
        error: '',
        isFetching: false,
        messages: action.messages
      })
    case FETCHING_MESSAGES_FAILURE:
      return state.merge({
        error: action.error,
        isFetching: false
      })
    default :
      return state
  }
}

export default messagesReducer

fetchMessages() simply returns a promise: -

export const fetchMessages = () => {
  return fetch(baseUrl + 'messages')
}

I am not going to post the component code here because it is not relevant to the issue.

So if I call fetchMessages() with an invalid URL to return a 404, state.messages becomes undefined in my component. This would seem to be being caused by this part of the function: -

        if (!r.ok) {
          dispatch(fetchingMessagesFailure(ERROR_MESSAGE))
        }else{
          return r.json()
        }

I think I might be confused regarding how to properly check and deal with potential errors in the returned Promise. According to the docs for fetch(), a 404 is not considered to be an error as (unlike regular AJAX) only network issues are considered to be a catch() type of error.

Can anyone pinpoint for me what is wrong with this part of my code? should I be using exit after dispatch(fetchingMessagesFailure(ERROR_MESSAGE)) to stop the following .then()? Also, even with just a 404, the .catch() block is also being run. This seems to be against what the docs suggest.

Any help greatly appreciated. Thanks.

U4EA
  • 832
  • 1
  • 12
  • 27

1 Answers1

1

I see you are using the same action on !r.ok and catch... so I would recommend to break the chain in case of !r.ok via throwing an error:

fetchMessages()
  .then((r) => {
    if (!r.ok) {
      throw true; // just go to .catch()
    }
    return r.json()
  })
  .then((b) => dispatch(fetchingMessagesSuccess(b)))
  .catch(() => dispatch(fetchingMessagesFailure(ERROR_MESSAGE)))
dhilt
  • 18,707
  • 8
  • 70
  • 85