simon sjöö
simon sjöö

Reputation: 395

React & Axios - Not receiving response data upon page refresh

Working on a project here and ran into an issue. I haven't had this problem before but now I do for some reason.

So I am making an GET request to ASOS API, but it is acting very strange. Some of these, such as name is received upon page refresh, but mainly the other things like information about the brand becomes undefined. Now, the brand is in another object inside of the API. But I have had other things at other parts of the page before that were also in objects. But I did not have any issue there.

Here is how the API call looks like: enter image description here

And here is my code for the API fetch:

const FetchAPI = (props) => {
  const [product, setProduct] = useState({});
  const [brand, setBrand] = useState({});
  const [price, setPrice] = useState({});

  const [params, setParams] = useState({
    id: "23363645",
    lang: "en-US",
    store: "US",
    sizeSchema: "US",
    currency: "USD",
  });

  useEffect(() => {
    const options = {
      method: "GET",
      url: "https://asos2.p.rapidapi.com/products/v3/detail",
      params: params,
      headers: {
        "x-rapidapi-key": "",
        "x-rapidapi-host": "",
      },
    };

    axios
      .request(options)
      .then(function (response) {
        console.log(response.data);
        setProduct(response.data);
        setBrand(response.data.brand);
        setPrice(response.data.price.current);
      })
      .catch(function (error) {
        console.error(error);
      });
  }, []);

  return (
    <div>
      <Product
        name={product.name}
        price={price.text}
        brand={brand.description.replace( /(<([^>]+)>)/ig, '')}
      />
    </div>
  );
};

I am sending the data over to Product which is the product page of the item I am requesting. But whenever I refresh the page, I get TypeError: Cannot read property 'replace' of undefined. I did remove replace, and it worked fine. And if I placed replace back into the brand.description and saved, still worked fine. But on the page refresh, it crashes.

Is it perhaps trying to load my return before the useEffect? If so, how do I solve this?

Upvotes: 1

Views: 2908

Answers (4)

Shyam
Shyam

Reputation: 5497

useEffect gets called only after the component is rendered . So when the component is rendered for the first time you have the state brand as an empty object . So what you are trying to do is {}.description -> . This is undefined .

This is the reason why its a good practice to always have a loading state when the component is making an api call.

const [ loading, setLoading ] = useState(true);

const getProductDetails = async() => {

  const options = {
  method: "GET",
  url: "https://asos2.p.rapidapi.com/products/v3/detail",
  params: params,
  headers: {
    "x-rapidapi-key": "",
    "x-rapidapi-host": "",
  },
 };
 try {
   const { data } = await axios.request(options);
   setProduct(data);
   setBrand(data.brand);
   setPrice(data.price.current);
  }
 catch(error){
   console.log(error)
 } finally {
   setLoading(false)
 }
}

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

if(loading)
  return <p> Loading ... </p>

return (
  // return your JSX here
 )

Upvotes: 0

Prince Mittal
Prince Mittal

Reputation: 326

The useEffect hook gets called once the component is rendered so in this case initially when your API is not called your brand.description will be undefined and when you are trying to use replace on undefined the error is coming. So you can always add a check using optional chaining(?.) so even if we don't get the description in the brand it will not break the website and you should also use a loader till the API call is through.

<div>
  <Product
    name={product.name}
    price={price.text}
    brand={brand.description?.replace( /(<([^>]+)>)/ig, '')}
  />
</div>

Upvotes: 0

Ron B.
Ron B.

Reputation: 1540

First of all, unrelated to your question, you have many superfluous state variables. You have product which stores all the data of the product and then price and brand which stores subsets of the same data. Consider using only the product state variable, or if you want to keep the names do something like

const price = product.price.current;

Second, your default value for brand is an empty object, meaning brand.description is undefined.

You can solve this with optional chaining like so:

 <Product
        name={product?.name}
        price={price?.text}
        brand={brand?.description?.replace( /(<([^>]+)>)/ig, '')}
      />

Upvotes: 1

Kanhaiya Mishra
Kanhaiya Mishra

Reputation: 53

I think the issue here is that while data from API is being fetched, brand.description is undefined and there is no replace method on undefined. You can either do this - >

<div>
  <Product
    name={product.name}
    price={price.text}
    brand={brand.description ? brand.description.replace( /(<([^>]+)>)/ig, '') : ""}
  />
</div>

or

const [brand, setBrand] = useState({ description: ""});

and keep the remaining code same.

Upvotes: 1

Related Questions