Reputation: 53
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.
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 });
};
Upvotes: 1
Views: 61
Reputation: 317
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.
Upvotes: 2