1

I have been able to pull data from an API that I built using MongoDB and Express, but am having trouble rendering the nested data to my React component.

For example, if I type in <p>{restaurant.cuisine}</p> I am able to retrieve Burgers, American, but if I try and access {restaurant.status.delivery}, I get an error that says:

Cannot read property 'delivery' of undefined.

But if I {console.log(restaurant.status} I can see the object? I tried turning the object into an array using Object.values, but that didn't work either.

enter image description here

The same thing happens if I try to access the nested objects in {restaurant.images} and {restaurant.geometry}.

Here's a copy of my React hook:

import { useReducer, useEffect } from 'react';
import axios from 'axios';

const ACTIONS = {
  MAKE_REQUEST: 'make-request',
  GET_DATA: 'get-data',
  ERROR: 'error',
};

function reducer(state, action) {
  switch (action.type) {
    case ACTIONS.MAKE_REQUEST:
      return { loading: true, restaurant: [] };
    case ACTIONS.GET_DATA:
      return {
        ...state,
        loading: false,
        restaurant: action.payload.restaurant,
      };
    case ACTIONS.ERROR:
      return {
        ...state,
        loading: false,
        error: action.payload.error,
        restaurant: [],
      };
    default:
      return state;
  }
}

export default function useFetchSingleRestaurant({ id }) {
  const [state, dispatch] = useReducer(reducer, {
    restaurant: [],
    loading: true,
  });

  useEffect(() => {
    dispatch({ type: ACTIONS.MAKE_REQUEST });
    axios
      .get('http://localhost:4444/restaurants/' + id)
      .then((res) => {
        dispatch({
          type: ACTIONS.GET_DATA,
          payload: { restaurant: res.data.restaurant },
        });
      })
      .catch((e) => {
        dispatch({
          type: ACTIONS.ERROR,
          payload: { error: e },
        });
      });
  }, [id]);

  return state;
}

I'm accessing it in my SingleRestaurant component:

function SingleRestaurant({ match }) {
  const { restaurant } = useFetchSingleRestaurant({ id: match.params.id });

  return ( 
    <p>{restaurant.status.delivery}</p>
  ) 
}

And then here's my backend setup as well:

showRestaurant = async (req, res) => {
  const restaurant = await Restaurant.findById(req.params.id)
    .populate({ path: 'reviews', populate: { path: 'author' } })
    .populate('author');
  if (!restaurant) {
    req.flash('error', 'Restaurant not found.');
    return res.redirect('/restaurants');
  }
  res.send({ restaurant });
};

1 Answer 1

2

Until your server request returns restaurant it will be set as the default [] that you have set.

An empty array does not have a property of status, so hence the error.

if you change your default to null:

const [state, dispatch] = useReducer(reducer, {
    restaurant: null,
    loading: true,
  });

And then check for a value:

function SingleRestaurant({ match }) {
  const { restaurant } = useFetchSingleRestaurant({ id: match.params.id });
  if (!restaurant) return 'Loading'

  return ( 
    <p>{restaurant.status.delivery}</p>
  ) 
}

You could also pass back the loading state from your hook and then do a check on that.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.