Search code examples
javascriptreactjsuse-effect

Using .map() with useEffect and Api


I am trying to use the useEffect to grab some data from an API. I am succesful in grabbing the data but after I set my state and try to map through it I just get "Can't read map of undefined". I think the problem is that it's running my .map() code before it gets the response. i am just unsure of how to solve this

This is the api response:

data: {count: 87, next: "https://swapi.co/api/people/?page=2", previous: null, results: Array(10)}

Here is my code

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './App.css';
import CharacterMap from './characterMap'

const App = () => {
  let [getChars, setChars] = useState(0);
  useEffect(() => {
    axios.get(`https://swapi.co/api/people/`)
      .then(res => setChars(res) )
  },[]);
 console.log(getChars.data.map((e) => e))
  return (

    <div className="App">
      <CharacterMap info={getChars} />
    </div>
  );
}
export default App;

Solution

  • axios.get is an async function and you are trying to get the data outside of an async function which is no completed yet.

    You could use useEffect with dependency array which is equal to componentDidUpdate to get the data.

    Initialized the state with the same datatype that you expect, in this case we expect an array you initialized ith with empty array.

    import React, { useState, useEffect } from 'react';
    import axios from 'axios';
    import './App.css';
    import CharacterMap from './characterMap'
    
    const App = () => {
      let [chars, setChars] = useState([]);
      useEffect(async () => {
        try{ 
          let response = await axios.get(`https://swapi.co/api/people/`)
          let data = await response.json();
          setChars(data);
        } catch(error) {
           console.error(error.message);
        }
      },[]);
     // If you want to access the updated state then use this.
      useEffect(() => {
         let newState = chars.map((e) => e); // map your state here
         setChars(newState); // and then update the state
         console.log(newState);
      },[getChars]);
    
      return (
    
        <div className="App">
          <CharacterMap info={chars} />
        </div>
      );
    }
    export default App;
    

    The second useEffect hook trigger on each state update and so you can get the updated state here.

    It will also trigger a re-render so you can also use the map in return statement;

    Or you could update the data on axios response and then set the state. Recommended

    useEffect(async () => {
        try{ 
          let response = await axios.get(`https://swapi.co/api/people/`)
          let data = await response.json();
          let newState = data.map((e) => e); // map your state here
          setChars(newState); // and then update the state
          console.log(newState);
        } catch(error) {
           console.error(error.message);
        }
      },[]);