0

I am pulling data from an internal API that returns an image that I am trying to display. I have a page function that is set to display the information from that response. The response is as follows for a single bottle

{
   "data":{
      "id":"cc134653-c463-4e79-8b9e-f52dfe02498e",
      "type":"bottle",
      "attributes":{
         "name":"Luc Belaire Rare Luxe",
         "price":"$29.99",
         "image":"https://cdn11.bigcommerce.com/s-7a906/images/stencil/1000x1000/products/10929/10518/Luc-Belaire-Rare-Luxe__73902.1555086630.jpg?c=2",
         "sku":"813497005010",
         "size":"750ML",
         "origination":"France",
         "varietal":"Sparkling Wine"
      }
   }
}

I am new to React so I could be mistaken here, but this function is intended to display a loader, just a simple fontawesome spinner, until the data is available.

Here is the function

import React, { useState, useEffect } from 'react';
import { Loader } from '../../components/Loader'
import { endpoints } from "../../utils/fetch";

export default function Bottle({ match }) {
  let [bottle, setBottle] = useState([])

  useEffect(() => {
    fetch(`${endpoints().bottle}/${match.params.sku}`, { method: "GET" })
    .then(response => response.json())
    .then(data => setBottle(data.data))
  }, [])

  return (
    !bottle ? <Loader /> :
    <div className="card">
      <div className="card-body">
        <div className="row">
          <div className="mb-4 mb-lg-0 col-lg-6">
            <div>
              <div className="position-relative h-sm-100 overflow-hidden">
                <img className="img-fluid fit-cover w-sm-100 h-sm-100 rounded cursor-pointer" 
                  src={bottle.attributes.image} 
                  alt={bottle.attributes.name} 
                  height={200}
                  width={125} />
              </div>
            </div>
          </div>
          <div className="d-flex justify-content-between flex-column col-lg-6">
            <div>
              <h5>Apple iMac Pro (27-inch with Retina 5K Display, 3.0GHz 10-core Intel Xeon W, 1TB SSD)</h5>
              <a className="fs--1 mb-2 d-block" href="#!">Computer &amp; Accessories</a>
              <h4 className="d-flex align-items-center"><span className="text-warning mr-2">$1199.50</span></h4>
              <p className="fs--1 mb-1"><span>Shipping Cost: </span><strong>$50</strong></p>
              <p className="fs--1">Stock: <strong className="text-success">Available</strong></p>
            </div>
            <div className="row">
              <div className="col-auto">
                <button type="button" className="border-300 mr-2  btn btn-outline-danger btn-sm">
                  <svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="heart" className="svg-inline--fa fa-heart fa-w-16 mr-1" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
                    <path fill="currentColor" d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z" />
                  </svg>
                  282
                </button>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  )
}

I would expect, based on what I've written, that the loader would display until the bottle has is not null. Instead, I get the following error.

enter image description here

Am I misusing state here? I've tried to use async and await here but was not successful in getting the data to display. Just the same error.

2
  • so this error means that you have a truthy value in bottle, but it doesn't have a prop called attributes, so you get this error, could you check and update your question with what is the value of bottle? is it still [] which means that setting it doesn't happen, could you also check what is returned exactly from you request in devTools and if there's any error in the console Commented Jan 20, 2021 at 18:41
  • Hi @Trenton. I've answered your question; if it solves your problem, please click on the tick button next to my answer. But while I'm here, please edit your post to include the actual error message as quoted text rather than a screenshot. Here is a post explaining why its generally unhelpful to post screenshots of errors. Even though I have probably solved your problem, Stack Overflow posts are resources for other people so its good to keep them as easy to read as possible. Commented Jan 20, 2021 at 19:03

1 Answer 1

1

Your default value for bottle is [], in JavaScript, an empty array is still considered truthy, so this will result in your component following the else path before your data has finished loading.

Also, when you are rendering the component, you are not using the data as an array anyway.

Change your useState to this:

let [bottle, setBottle] = useState();

This will provide a default value of undefined to bottle, which should mean your ternary will behave correctly.

Sign up to request clarification or add additional context in comments.

Comments