Search code examples
reactjsobjectreduxrendering

Objects are not valid as a React child (found: object with keys {_id, date, createdAt, updatedAt, __v})


I get the following error when i try to render an object ({day} see react Component below) coming from the database:

Error: Objects are not valid as a React child (found: object with keys {_id, date, createdAt, updatedAt, __v}). If you meant to render a collection of children, use an array instead.

The object in question looks like this:

{
  "_id": "5fdf554b88f52f520c93a16e",
  "date": "2020-12-20T10:00:00.133Z",
  "createdAt": "2020-12-20T13:44:43.934Z",
  "updatedAt": "2020-12-20T13:44:43.934Z",
  "__v": 0
}

And the following is my code:

Router:

dayRouter.get(
  '/:id',
  expressAsyncHandler(async (req, res) => {
    const day = await Day.findOne({ _id: req.params.id })
    if (day) {
      res.send(day);
    } else {
      res.status(404).send('Booking Not Found.');
    }
  })
);
export default dayRouter;

Redux-Action:

export const detailsDate = (dayId) => async (dispatch) => {
  try {
    dispatch({ type: DATE_DETAILS_REQUEST, payload: dayId });
    const { data } = await Axios.get(`/api/day/${dayId}`);
    dispatch({ type: DATE_DETAILS_SUCCESS, payload: data });
  } catch (error) {
    dispatch({
      type: DATE_DETAILS_FAIL,
      payload:
        error.response && error.response.data.message
          ? error.response.data.message
          : error.message,
    });
  }
};

Redux-Reducer:

export function dateDetailsReducer(
    state = {loading: true}, action) {
    switch (action.type) {
      case DATE_DETAILS_REQUEST:
        return { loading: true };
      case DATE_DETAILS_SUCCESS:
        return { loading: false, day: action.payload };
      case DATE_DETAILS_FAIL:
        return { loading: false, error: action.payload };
      default:
        return state;
    }
  }

React Component:

import { useDispatch, useSelector } from 'react-redux';
import { detailsDate } from '../actions/dateAction';

function BookingConfirmationScreen(props) {  

  const dayId = props.match.params.id;

  const dateDetails = useSelector((state) => state.dateDetails); //from Redux Store
  const { day } = dateDetails;

  const dispatch = useDispatch();
  useEffect(() => {

      dispatch(detailsDate(dayId));
    return () => {};
  }, [day,dispatch, dayId]);

  return (
    <h1> Booking {day}</h1>
  )
}

export default BookingConfirmationScreen;

What i need to render is actually {day.date} but i get that day is actualli undefined. Which is when i realised that there is an issue with {day}


Solution

  • day is undefined because you get that data from the server, so rendering the component is faster than the async call. That is why you have loading in reducer, it is set to false when the data is recieved from the server. Destruct the loading from the state like this:

     const { day, loading } = dateDetails;
    .
    .
    .
    

    then do this in when you are returning:

    if(loading)
    return <div> loading.. </div>
     return (
        <h1> Booking {day.date}</h1>
      )