Search code examples
javascriptarraysreactjsmernarray-push

Javascript Array.push creating a nested array which I cannot access using the index


I have looked at the following articles, which all go into depth about asynchronous calls return undefined.

Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

Get data from fs.readFile

This doesn't answer my question, however. In my example, I am using async, and await, and .then. The async function IS returning something, and populating the array, however it is the format of the array, and the ability of dealing with the array that I am struggling with.

I am using the following code to populate an array with objects from my MongoDB database.

const initialClasses = [];

const getInitData = async () => {
  await axios.get('http://localhost:5000/classes/api/')
    .then(response => {
      initialClasses.push(response.data)
    })
    .catch(error => {
      console.log(error)
    });
  }
  getInitData();
  console.log(initialClasses);

When I console.log initialClasses, however, I get the following array:

[]
0: (3) [{…}, {…}, {…}] // objects provided from the async call
length: 1
__proto__: Array(0)

When I try to access this array, using console.log(initialClasses[0]); i get undefined.

What have I done wrong in creating this array? Is there a better, cleaner way to do this which I have overlooked? Thanks.


Solution

  • First I think I'd recommend revisiting Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference as your understanding of asynchronous behavior grows. I believe it's at the root of the problem here (hence why this feels like a duplicate to some members of the community).

    Why you get undefined when you call console.log(initialClasses[0]) will depend on when you call that and again we'd expect undefined if you call it too early and misunderstand how async works.

    But instead of getting into those weeds, let's get to the root of your question: Is there a cleaner way? Yes! Probably the misunderstanding here comes from the way you've structured this. You can simplify it a lot and get the same functionality.

    You can call the following inside of an async function

    const response = await axios.get('http://localhost:5000/classes/api/');
    let initialClasses = response.data;
    

    This would be the preferred way since whatever you are wanting to do with the response from that endpoint is fundamentally asynchronous. This way the response data won't be 'nested' either.