1

I am trying to learn how to fetch data and display in a table/list/graph in React.

I extracted the fetch to a component and while i can get the list to appear i think this is wrong - Why and how to fix?

// getData.tsx
import React, { useState, useEffect } from 'react';
    
let myArray: string[] = [];
export default function GetData() {  
    const [info, setData] = useState([]);
    
    useEffect(() => {
        getMyData();
    }, []);
    
    const getMyData = async () => {
        const response = await fetch('https://pokeapi.co/api/v2/type')
        const data =await response.json();
        //console.log(data.results)
        for (var i = 0; i < data.results.length; i++) {     
            myArray.push(data.results[i].name)   
            setData(data.results[i].name)
        }
        console.log(info)
    }
   
    return (
        <div>
            <h1>get Data</h1>
           {myArray.map((value,index) => {
               return <li key={index}>{value}</li>;
           })}
        </div>
    )
}

Also same issue but do not understand why the names and Array don't both work?

export default function GetData(){
    const names: string[] = ["whale", "squid", "turtle", "coral", "starfish"];
        
    const theArray: string[] = [];
        
    const getData = async () => {
        const response = await fetch('https://pokeapi.co/api/v2/type');
        const data = await response.json()
        
        //for (var i = 0; i < data.results.length; i++) {  
        for (var i = 0; i < 5; i++) {  
            theArray.push(data.results[i].name)
        }
        console.log(theArray)
    }
        
    console.log(names)
    console.log(theArray)
    
    getData()
        
    return (
        <div>
            <ul>{names.map(name => <li key={name}> {name} </li>)}</ul>
            <h1>get Data</h1>
            <ul>{theArray.map(name => <li key={name}> {name} </li>)}</ul>
        </div>
    )
}

2 Answers 2

2

You aren't using the state data... The issue is that.

The correct way to do this:

const [data, setData] = useState([])
useEffect(() => {
  fetch('https://pokeapi.co/api/v2/type')
  .then(res => res.json())
  .then(setData)
},[])

return <div>
 <ul>
  {data.map((name) => <li key={name}>{name}</li>}
 </ul>
</div>
Sign up to request clarification or add additional context in comments.

Comments

1

The problem is getData is declared as async function. That means it's returning Promise that you can await on and get it's result. But you never do that. You're using it without await essentially not waiting for it finish and discarding its result.

To get the result of async function you should await on it. In your second component you'll have to write this:

    ...
    console.log(names)
    console.log(theArray)
    
    await getData() // add 'await' to well... wait for the result of the getData execution
        
    return (
    ...

But you can await only inside async function aswell. As far as I'm concerned you're not able to use async components now (react@16-17). So the second component is not going to work as intended. At least untill react is able to support async components.

Though there are some issues even with your first component.

let myArray: string[] = [];

Declared in the module scope it will be shared (and not reseted) between all instances of your component. That may (and will) lead to very unexpected results.

Also it's quite unusuall you don't get linting errors using getMyData before declaring it. But I suppose that's just an artefact of copy-pasting code to SO.

Another problem is you're using setData inside your component no to set the contents of myArray but to trigger rerender. That's quite brittle behavior. You should directly set new state and react will trigger next render and will use that updated state.

To work properly your first component should be written as:

import React, { useState, useEffect } from 'react'
    
export default function GetData() {  
    const [myArray, setMyArray] = useState([])
    
    const getMyData = async () => {
        const response = await fetch('https://pokeapi.co/api/v2/type')
        const data = await response.json()
        const names = data.results.map((r) => r.name) // extracting 'name' prop into array of names

        setMyArray(names)
    }

    useEffect(() => {
        getMyData();
    }, []);
   
    return (
        <div>
            <h1>get Data</h1>
            {myArray.map((value,index) => (
                <li key={`${index}-${value}`}>{value}</li>
            ))}
        </div>
    )
}

3 Comments

Your post was very helpful however i still get typescript error, stated as Parameter 'r' implicitly has an 'any' type.ts(7006) (parameter) r: any
had to change to const names = data.results.map((r:any) => r.name), now works - thanks:)
don't forget todo this: {myArray && myArray.map ....}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.