Sajedul Noman
Sajedul Noman

Reputation: 1

best practices for dispatch an action and get the state from redux in same component?

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

Answers (1)

Erfan
Erfan

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

Related Questions