4

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;
4
  • What is the purpose of that map call? It just creates a new array with the same information, like slice() would. Commented Mar 8, 2020 at 13:44
  • 1
    well after I get the .map working I will use it to extract more data. Commented Mar 8, 2020 at 13:50
  • Gotcha. FWIW, I think you want res => setChars(res.data.results) or res => setChars(res.results) (this is after you change 0 to [] in useState so it's always an array). That would also probably be where you'd extract the data you want, rather than later. So res => setChars(res.data.results.map(/*...*/)). Commented Mar 8, 2020 at 13:54
  • 1
    Also, the name getChars makes it look like a function. Since it's data, I suggest just calling it chars. Commented Mar 8, 2020 at 13:55

3 Answers 3

5

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);
    }
  },[]);
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! I didn't think you could use useEffect more than one time on each page for some reason!
You could add useEffect multiple time as required.
this answer is wrong and misleading: useEffect shouldn't be an async function, because an async function returns a promise, but the return value of the useEffect function is used for cleanup.
1

Keep the default values as array

let [getChars, setChars] = useState([]);

Comments

-1

you are setting data to array chars. instead of that set array(results) that you are getting in response.

As you defined let [getChars, setChars] = useState([]);

useEffect(() => {
   function getData() {
    axios
    .get(`https://swapi.co/api/people/`)
    .then(res=> setChars(res.data.results))
    .catch(err=> console.log(err))
   }

   getData();
  },[]);

1 Comment

this answer is wrong and misleading: useEffect shouldn't be an async function, because an async function returns a promise, but the return value of the useEffect function is used for cleanup.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.