Reputation: 1
I have a component, where I am dispatching get product action which fetches product by slug. I am getting the result from redux store by useSelector and display the result. I am getting error as follows: "Uncaught TypeError: Cannot read property 'primary' of undefined"
I think, this is because the component renders before I am getting the product value from redux. my code as follows:
//dependencies
import { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { useParams } from "react-router-dom";
//components
//content container
import ContentContainer from "../ContentContainer";
//title
import Title from "../Title";
//actions
import { getSingleProductAction } from "../../../redux/common/actions/productActions";
const ViewProduct = () => {
const { product, productLoading } = useSelector(
(state) => state.productReducer
);
const { slug } = useParams();
const dispatch = useDispatch();
useEffect(() => {
dispatch(getSingleProductAction(slug));
}, [slug, dispatch]);
return (
<>
{/************ Title ************/}
<Title title="View Product" />
{/************ Content ************/}
<ContentContainer>
{productLoading ? (
<div className="">Loading...</div>
) : (
<div className="grid grid-cols-1 sm:grid-cols-5 gap-2 mx-1 pb-3">
<div className="col-span-1 sm:col-span-2">
<div className="w-full mb-3">
<img
src={product.images.primary}
alt={product.brand + " " + product.model}
className="rounded mx-auto sm:mx-0 sm:w-full"
/>
</div>
<div className="grid grid-cols-2 gap-1">
{product.images.secondary.map((img, index) => (
<img
key={index}
className="w-full rounded"
src={img}
alt={product.brand + " " + product.model}
/>
))}
</div>
</div>
<div className="col-span-1 sm:col-span-3"></div>
</div>
)}
</ContentContainer>
</>
);
};
export default ViewProduct;
How to render the component after the product is fetched? I am wondering what is the best practice for this kind of situation.
Regards
Upvotes: 0
Views: 454
Reputation: 1812
You can use AND logical operator to first check if product is truthy then render the html.
{productLoading ? (
<div className="">Loading...</div>
) : product && ( //check here
<div className="grid grid-cols-1 sm:grid-cols-5 gap-2 mx-1 pb-3">
<div className="col-span-1 sm:col-span-2">
<div className="w-full mb-3">
<img
src={product.images.primary}
alt={product.brand + " " + product.model}
className="rounded mx-auto sm:mx-0 sm:w-full"
/>
</div>
<div className="grid grid-cols-2 gap-1">
{product.images.secondary.map((img, index) => (
<img
key={index}
className="w-full rounded"
src={img}
alt={product.brand + " " + product.model}
/>
))}
In JavaScript, expression1 && expression2
is processed like this:
If expression1 is truthy, expression2 is returned.
If expression1 is falsy (null or undefined), the first expression is returned. (null or undefined are rendered as simply nothing in React)
Upvotes: 1