0

Let me start off by saying that I did look for other topics but I haven't found a solution yet so I'd like to walk through this with you guys.

I have a simple website with a search bar, a search result list and a div where I display the item I click in the result list.

The issue starts when I click an item in the results list. I need to click it twice for it to update the div where I display the item.

What happens when I click an item from the search results list:

const getProductById = (store) => {
if (store == "STORENAME") {
  Axios.get(
    `http://localhost:3001/get-storename-product-by-id/${productId}`
  ).then((response) => {
    console.log(response.data);
    setProductResultList(response.data);
    setProductTitle(response.data[0].title);
    setProductImg(response.data[0].imageSrc);
    setFinalProductId(response.data[0].productId);
  });
} else {
  Axios.get(`http://localhost:3001/get-storename-product-by-id/${productId}`).then(
    (response) => {
      console.log(response.data);
      setProductResultList(response.data);
      setProductTitle(response.data[0].title);
      setProductImg(response.data[0].imageSrc);
      setFinalProductId(response.data[0].productId);
    }
  );
}

};

The function fetches all the data linked to the productId of the clicked product (this returns all the historic data I have on the item in an array with objects (1 object for each row)).

How I show the item on the page:

<div className="item">
              <div>
                <img
                  src={productImg}
                  alt={productTitle}
                  width="250px"
                  height="250px"
                />
                <p className="product-id-span">
                  Product Id: {finalProductId}
                </p>
                <p className="m-0">Product name:</p>
                <p>{productTitle}</p>
                <div className="historical-info">
                  <span>latest prices:</span>
                  <div className="table-responsive">
                    <table class="table text-white">
                      <thead>
                        <tr>
                          <th scope="col">Price</th>
                          <th scope="col">Date</th>
                        </tr>
                      </thead>
                      <tbody>
                        {productResultList.map((val, key) => {
                          let parsedPrice = parseInt(val.price);
                          let parsedPriceInEuros = parsedPrice / 100;
                          const finalPrice = new Intl.NumberFormat(
                            "de-DE",
                            { style: "currency", currency: "EUR" }
                          ).format(parsedPriceInEuros);
                          return (
                            <tr>
                              <td>
                                Price:
                                {val.store == "STORENAME"
                                  ? finalPrice
                                  : val.price}
                              </td>
                              <td>{val.date}</td>
                            </tr>
                          );
                        })}
                      </tbody>
                    </table>
                  </div>
                </div>
              </div>
            </div>

What I've tried:

I tried to only set state to the productResultList in the getProductById function, and set the other state when the useEffects note changes to the productResultList.

 useEffect(() => {
   setProductTitle(productResultList[0].title);
   setProductImg(productResultList[0].imageSrc);
   setFinalProductId(productResultList[0].productId);
 }, [productResultList]);

Could someone perhaps explain what I'm doing wrong or what's the right way to do this?

Note:

  • I changed the real store names to STORENAME because it's not neccessary in this example.
  • resultList = the list with results when I search, productResultList is the list with objects of the clicked product.
sneaker
  • 49
  • 2
  • 8
  • I suggest you start using RTK and RTK query to get rid of the boilerplate, as I see you‘re trying to set up a redux store. – GabeRAMturn Jul 05 '22 at 09:50
  • @gabeRAMturn I just use react state , not redux. Or do you mean what I'm trying to do is how Redux is used? – sneaker Jul 05 '22 at 09:54
  • Yes, I think redux with RTK and RTK query might help immensly with maintaining such a complex state tree, including the API calls. – GabeRAMturn Jul 09 '22 at 10:54

1 Answers1

0

So the solution to this problem was fairly different to what I expected. The function that initializes getProductById() sets state to productId first so I can use that in my request as you can see.

Because setting state is asynchronious, the productId was not available on the first request.

I fixed this by passing the productId as a parameter to the getProductById function so it does not have to wait for the state to be changed.

sneaker
  • 49
  • 2
  • 8
  • Congrats. You can accept your own answer & add post the updated code in your answer, so that it can help others. – Nice Books Jul 05 '22 at 13:29