-2

I'm still slightly confused about map. When I comment out the map my h2 renders, what am I doing wrong? Yes I would still like to use fetch. I need to understand what I'm doing wrong before I add more depth to it.

import { useState, useEffect } from "react";

export default function SearchAPI() {

    const [cocktail, setCocktail] = useState()
    

    useEffect(() => {
        fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita')
        .then(res => res.json())
            .then(data => {
            setCocktail(data.drinks[0])
            console.log(cocktail)
            
           
        })
        .catch(err => {
            console.log(`error ${err}`)
        })
    }, [])

    return (
        <>
            <h2>here is your drink</h2>
            {cocktail.map((element) => {
                return <h2>{element.strDrink}</h2>
                
                
            })}
        </>
    )
}

When I comment out the function it renders.

halfer
  • 19,824
  • 17
  • 99
  • 186

2 Answers2

0

When I comment out the map my h2 renders, what am I doing wrong?

The h2 is outside the map(), so if the cocktail is empty, you'll still render the h2.


You probably only want to render the h2 if cocktail has some data.

You can add a default value to the state (useState({})) and then use Object.keys(coctail).length === 0 to check if there are any values in the object.

Then using (condition) ? <>content with data</> : <>loading</> to render the h2 and map() or a loading message.

Where you loop over the object to render all the info


Example:

const { useState, useEffect } = React;

const SearchAPI = () => {

    const [cocktail, setCocktail] = useState([])
    
    useEffect(() => {
        fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita')
        .then(res => res.json())
        .then(data => setCocktail(data.drinks[0]) )
        .catch(err => console.log(`error ${err}`))
    }, [])

    return (
        <React.Fragment>
            {
                (Object.keys(cocktail).length > 0) 
                  ? (
                        <React.Fragment>
                            <h1>here is your drink</h1>
                            {Object.keys(cocktail).map((key, index) => (
                                <React.Fragment>
                                    <div class='row'>
                                        <h3>{key}</h3>
                                        <em>{cocktail[key]}</em>
                                    </div>
                                </React.Fragment>
                            ))}
                        </React.Fragment>
                    )
                  : <em>{'Loading data'}</em>
            }            
        </React.Fragment>
    )
}
ReactDOM.render(<SearchAPI />, document.getElementById("react"));
.row {
    width: 50vw;
    display: flex;
    flex-direction: column;
    padding-bottom: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
0stone0
  • 34,288
  • 4
  • 39
  • 64
  • There is nearly never any value in asking for a reason for a comment. If the voter did not provide any feedback when voting, they wish to remain anonymous, as is their right. That is a key design feature of voting on Stack Overflow. – halfer Feb 01 '23 at 17:54
0

It sounds like you're trying to use the map() method on an object, which won't work. The map() method is an array method that can only be used on arrays.

If you're trying to access data from an object, you'll need to use dot notation to access the individual object properties. For example, if you have an object cocktail and you're trying to access the strdrink property, you would do it like this: cocktail.strdrink.

If you have set cocktail to data.drinks[0], this will access the first object in the drinks array.

Change this:


    {cocktail.map((element) => {
      return <h2>{element.strDrink}</h2>
    })}

to that:


    {cocktail && <h2>{cocktail.strDrink}</h2>}

// Get a hook function
const {useState, useEffect} = React;

const Example = () => {
    const [cocktail, setCocktail] = useState()
    
    useEffect(() => {
   fetch('https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita')
        .then(res => res.json())
            .then(data => {
            setCocktail(data.drinks[0])
        })
        .catch(err => {
            console.log(`error ${err}`)
        })
    }, [])
   
    return (
        <div>
            <h2>here is your drink</h2>
            {cocktail && <h2>{cocktail.strDrink}</h2>}
        </div>
    );
};

// Render it
ReactDOM.createRoot(
    document.getElementById("root")
).render(
    <Example />
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.development.js"></script>