Home > Enterprise >  My map rendering in Reactjs, please help me to figure out why?
My map rendering in Reactjs, please help me to figure out why?

Time:02-01

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. I need to understand what I'm doing wrong before I add more depth to my project.

CodePudding user response:

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>

CodePudding user response:

well, you did not mention a particular error but as far as I see your code, you got a problem with fetch function. fetching data from an api is asynchronous, it means that when your react page renders, you have no actual data and it throws an error(because there is no element.strDrink), what you need to do is this: you need to check if the data is fetched or not, and render things according to that. so

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.length ? cocktail.map((element) => {
                return <h2>{element.strDrink}</h2>
                
                
            })  : "Loading data"}
        </>
    )
}

CodePudding user response:

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>

  • Related