Home > Net >  Fetching API data with React
Fetching API data with React

Time:12-19

So I'm trying to fetch data from my API and I'm able to log it into console, but I can't render it into my app using useState. Tried something like that and it completely ignores my h2.

var id = "61bf209bdb079818ec63d9fd";

const Main = () => {
    const [name, setName] = useState("");
    const [fromApi, setFromApi] = useState([]);
    
    const getApiData = () => {
        fetch('http://localhost:3000/myapi')
            .then(res => {
                return res.json();
            })
            .then(data => {
                console.log(data);
                setFromApi(data);
            })
        
        for (var i = 0; i < fromApi.length; i  ) {
            if (fromApi[i]._id === id) {
                setName(fromApi[i].name);
            }
        }
    }

    useEffect(() => {
        getApiData();
    }, [])
    
    return (
        <div>
            {name && <h2 className='urname'>Your name: {name}</h2>}
        </div>
    )
}

CodePudding user response:

This is happening because React does not guarantee that the state changes are applied immediately. This makes reading state right after updating (in your case setFromApi) a potential pitfall and can potentially return the existing value due to async nature.

React Doc: https://reactjs.org/docs/react-component.html?#setstate

In your case you're using data receiving from API and running for loop even before fromAPI state gets updated. Instead put fromAPI in dependency array to useEffect and perform your for loop there.

var id = "61bf209bdb079818ec63d9fd";

const Main = () => {
    const [name, setName] = useState("");
    const [fromApi, setFromApi] = useState([]);
    
    const getApiData = () => {
        fetch('http://localhost:3000/myapi')
            .then(res => {
                return res.json();
            })
            .then(data => {
                console.log(data);
                setFromApi(data);
            })
    }

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

    useEffect(() => {
      if(fromApi?.length){
        for (var i = 0; i < fromApi.length; i  ) {
            if (fromApi[i]._id === id) {
                setName(fromApi[i].name);
            }
        }
      }
    }, [fromApi])
    
    return (
        <div>
            {name && <h2 className='urname'>Your name: {name}</h2>}
        </div>
    )
}

CodePudding user response:

I would consider why you have two states of fromApi and name? You could just setName as soon as the data comes back from the API...something like:

    const [name, setName] = useState("");
    
    const getApiData = () => {
        fetch('http://localhost:3000/myapi')
            .then(res => {
                return res.json();
            })
            .then(data => {
                console.log(data);
                for (var i = 0; i < data.length; i  ) {
                    if (data[i]._id === id) {
                        setName(data[i].name);
                        // Stop the for loop once match has been found
                        return;
                    }
                }
            })
    }
  • Related