Search code examples
reactjsreduxreact-reduxreact-hooksredux-thunk

Following a tutorial: Uncaught TypeError: Cannot read properties of undefined (reading 'name')


here i am returning a jsx element the element renders and API is hitting but when i use product.name it's returning undefined

import { useAlert } from 'react-alert';

import { useDispatch, useSelector } from 'react-redux';

import { getProductDetails, clearErrors } from '../../actions/productActions';

const ProductDetails = ({ match }) => {

    const dispatch = useDispatch();

    const alert = useAlert();

    const { loading, error, product } = useSelector(state => state.productDetails)
    
    useEffect(() => { 

        dispatch(getProductDetails(match.params.id));
        
        if (error) {

            alert.error(error);

            dispatch(clearErrors());
        }
        
    }, [dispatch, alert, error, match.params.id])
    
return(console.log(product.name))


Solution

  • Since you are dispatching getProductDetails() after your first render, which basically means that you are calling the API after your component is mounted.

    useEffect(() => {},[]) runs after first render of React component, and when you are trying to access product.name, product is actually undefined because the API isn't even called in the first place.

    A solution would be to show a fallback loading screen, until you are finished loading. Make sure loading state is handled correctly though.

    const ProductDetails = ({ match }) => {
      const dispatch = useDispatch();
    
      const alert = useAlert();
    
      const { loading, error, product } = useSelector(
        (state) => state.productDetails
      );
    
      useEffect(() => {
        dispatch(getProductDetails(match.params.id));
    
        if (error) {
          alert.error(error);
    
          dispatch(clearErrors());
        }
      }, [dispatch, alert, error, match.params.id]);
    
      if (loading) {
        return <div>Loading...</div>;
      }
    
      return <div>{product.name}</div>;
    };