1

In a marketplace project, I want to show product information and store information like "more products from this store".

Currently my code does the following:

  1. Get the product ID from URL and make an API call using that ID to get the product information.
  2. State variable product is updated with that product information.
  3. The product object includes a storeName value which I try to use to make another API call to get the store information (more products from that store)

The last step doesn't work. The site loads and the product information is displayed correctly, however the JSON response from the store API call shows an error because the storeName value is null. The store information is not displayed.

Code:

function ProductPage() {
  const { productUrl } = useParams();
  const [product, setProduct] = useState([]);
  const [store, setStore] = useState([]);

  const {
    name,
    price,
    description,
    images,
    storeName
  } = product;

  useEffect(() => {
    getProduct();
    getStore();
  }, []);

  const getProduct = async () => {
    const product = await API.graphql(
      graphqlOperation(queries.productByProductId, {
        productId: productUrl,
      })
    );
    setProduct(product.data.productByProductId.items[0]);
  };
  const getStore = async () => {
    const store = await API.graphql(
      graphqlOperation(queries.storeByName, {
        name: storeName,
      })
    );
    setStore(store.data.storeByName.items[0]);
  };
Emile Bergeron
  • 17,074
  • 5
  • 83
  • 129
Luis Garcia
  • 125
  • 8

2 Answers2

1

You can use it , like this :

useEffect(() => {
    // called as soon as product state updates
    getProduct(); 
}, [product]); // watch for product state update

useEffect(() => {
    // called as soon as store state updates
    getStore();
}, [store]); // watch for store state update

NOTE :

You do not need second useEffect, due to "The product object includes a storeName" you should call getStore() from getProduct() as store value depends on product's store as @ShubhamKhatri is explaining, I have missed that point at first glance.

Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
1

getProduct and getStore are async operation and getStore is dependent on getProduct result other. Also you must note that state updates depend on the closure and are visible in the next render. So you need to call getStore inside getProduct. Also pass in the storeName as argument to getStore and do not take it from closure as it will refere to the old value

function ProductPage() {
  const { productUrl } = useParams();
  const [product, setProduct] = useState([]);
  const [store, setStore] = useState([]);

  const {
    name,
    price,
    description,
    images,
    storeName
  } = product;

  useEffect(() => {
    getProduct();
  }, []);

  const getProduct = async () => {
    const product = await API.graphql(
      graphqlOperation(queries.productByProductId, {
        productId: productUrl,
      })
    );
    getStore(product.data.productByProductId.items[0].storeName);
    setProduct(product.data.productByProductId.items[0]);
  };
  const getStore = async (storeName) => {
    const store = await API.graphql(
      graphqlOperation(queries.storeByName, {
        name: storeName,
      })
    );
    setStore(store.data.storeByName.items[0]);
  };
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • I just tried your code but keep getting the same error. Have any ideas what could be wrong? – Luis Garcia May 15 '20 at 18:26
  • 1
    @LuisGarcia My mistake, You need to call the getStore with correct arguments. `getStore(product.data.productByProductId.items[0].storeName);`. I edited my post. This should work for you and is actually the right way to go instead of adding another useEffect – Shubham Khatri May 15 '20 at 19:26