Banner Banner - 2 months ago 8
Javascript Question

Dealing with error when making fetch call in redux

I'm building a weather app that returns weather details for a particular city. Everything works fine when a valid location is entered. My problem occurs when I enter a junk string (ex. 'afasdfldsakfh') into the search field and press enter. This makes sense as the api call should not find the location.

I get the following error in the console:

Uncaught TypeError: Cannot read property 'observation_location' of undefined


This is coming from the reducer under the RECEIVE_WEATHER case. I'm not sure what I need to do when the payload is not valid and missing the info I need to set the props for my state. Any help will be greatly appreciated, thanks!

export function receiveWeather(json) {
console.log(json);
return {
type: RECEIVE_WEATHER,
payload: json
};
};

export function fetchingWeather(location) {
const init = {
method: 'GET'
};
return dispatch => {
dispatch(requestWeather())
return fetch(weatherUrl + location + '.json', init)
.then(response => response.json())
.then(json => dispatch(receiveWeather(json)))
};
};

export function weather(state = {
isFetching: false,
city: '',
country: '',
weather_image: '',
weather_description: '',
weather_number: '',
wind_dir: '',
wind_speed: '',
humidity: '',
precipitation: ''
}, action) {
switch (action.type) {
case REQUEST_WEATHER:
return Object.assign({}, state, {
isFetching: true
});
case RECEIVE_WEATHER:
return Object.assign({}, state, {
isFetching: false,
city: (action.payload.current_observation.observation_location.full),
country: (action.payload.current_observation.observation_location.country),
weather_image: (action.payload.current_observation.icon_url),
weather_description: (action.payload.current_observation.weather),
weather_number: (action.payload.current_observation.temp_c),
wind_dir: (action.payload.current_observation.wind_dir),
wind_speed: (action.payload.current_observation.wind_kph),
humidity: (action.payload.current_observation.relative_humidity),
precipitation: (action.payload.current_observation.precip_today_in)
});
default:
return state
};
};

Answer

In your fetch call use attach an error handler like so:

return fetch(weatherUrl + location + '.json', init)
  .then(response => response.json())
  .then(json => dispatch(receiveWeather(json)))
  .catch(err => handleError(err))

I don't know what implementation of fetch you're using but there's generally a catch or error method on the api.

You can also add a case that handles the error as such:

case RECEIVE_WEATHER_ERROR: 
   return ...

and in that case you may as well dispatch the error in the error handler

return fetch(weatherUrl + location + '.json', init)
  .then(response => response.json())
  .then(json => dispatch(receiveWeather(json)))
  .catch(err => dispatch(handleError(err)))

handleError can be implemented just like your other functions:

function handleError(err) {
  return {
    type: RECEIVE_WEATHER_ERROR,
    payload: err
  }
}

If you're not getting an error back but instead an empty json object where payload.current_observation is undefined

In your case statement add the following:

case RECEIVE_WEATHER:
  if (!action.payload.current_observation) return state
  ...