Async operation is not completing - React

Async operation is not completing - React
0

#1

I am trying to map through an array to complete an async operation but what I’m getting back is the promise pending, not the actual object.

const movies = [];

let queryString =
  "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=###&page=";

for (let i = 1; i < 11; i++) {
  movies.push({ number: i, query: queryString + i });
}
async componentDidMount() {
  const promise = movies.map(movie => axios.get(movie.query));
  const allMovies = await promise
  console.log(allMovies);
 }

The output is the following:

The actual object should be like this:


#2

You must await every axios.get instead of mapping through it and awaiting later. Try this:

async componentDidMount() {
  const allMovies = movies.map(movie => await axios.get(movie.query));
  console.log(allMovies);
 }

#3

I tried that, I get a syntax error

Syntax error: await is a reserved word


#4

It makes sense, we’re calling await in componendDidMount, we must call it in the map callback. Try this:

async componentDidMount() {
  const allMovies = await Promise.all(movies.map(async (movie) => await axios.get(movie.query)));
  console.log(allMovies);
}

#5

That works, thank you.

Now I’m trying to concatenate everything into one final array of objects, look at this image:

I’d like to get the object.data.results of each object:

async componentDidMount() {
    const allMovies = await Promise.all(
      movies.map(async movie => await http.get(movie.query))
    );
    console.log(allMovies);
    const movies = allMovies.map(movie => movie.data.results);
    console.log(movies);
  }

Basically I’m trying to get an array of objects with 200 items. As you can see in the image above every each array of has 20 movie objects, I want to concatenate all those movies objects into one final array.

const result = [{...}]
result.length // output: 200

I could do it like this:

const { data: res1 } = await http.get(movies[0].query);
const { data: res2 } = await http.get(movies[1].query);
etc...

const allMovies = [...res1.results, ...res2.results];
console.log(allMovies);

But Im sure there must be a better way.


#6

Why are you using res1, res2, res3? This probably should have been an array in the first place. For example, instead of doing this:

const { data: res1 } = await http.get(pages[0].query);
const { data: res2 } = await http.get(pages[1].query);
etc...

You should be doing this:

final results = await Promise.all(pages.map(async page => await http.get(page.query)))

#7

Basically Im just trying to figure out a better way to do this:

async componentDidMount() {
    const { data: res1 } = await http.get(allMovies[0].query);
    const { data: res2 } = await http.get(allMovies[1].query);
    const { data: res3 } = await http.get(allMovies[2].query);
    const movies = [...res1.results, ...res2.results, ...res3.results];

    this.setState({ movies });
  }

Considering that the length of my allMovies array could vary or might be a bit to long for me to hardcode everything they I did it.

const allMovies = [];

let queryString =
  "https://api.themoviedb.org/3/discover/movie?sort_by=popularity.desc&api_key=###&page=";

for (let i = 1; i < 11; i++) {
  movies.push({ number: i, query: queryString + i });
}

#8

I managed to concatenate all objects into one array as I wanted:

async componentDidMount() {
    const dataArr = await Promise.all(
      allMovies.map(async movie => await http.get(movie))
    );

    const movies = [];
    for (let i = 0; i < dataArr.length; i++) {
      movies.push(...dataArr[i].data.results);
    }
    console.log(movies);

    this.setState({ movies });
  }

The for loop works but it looks a bit ugly there, I would like to do the same using map instead since is much cleaner but no luck so far.

const result = dataArr.map(movie => movie.data.results);
console.log(result);

The first array represents the for loop, the second the map method.


#9
const movies = dataArr.map(movie => movie.data.results).flat()

Flat is still experimental: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat

You can also do like this if you don’t want to use flat:

const movies = [].concat.apply([], dataArr.map(movie => movie.data.results))

#10

This is exactly what I was looking for, thanks a lot dude. Flat is a lot cleaner and it’s only not supported in IE, which I don’t care too much honestly, still I think I’ll go with the second method. Would you be so kind to explain the syntax for the second method?

[].concat.apply([], ...)

On a side note, just realized the maximum amount of items in an array is 100? If so, why is that? Everything seems to be concatenated into one array but the console shows the array split in 2 arrays of 100 items each.


#11

There’s no limit to the amounts of items in an array. Maybe it is chrome developer tools trying to make it easier for you to visualize your data?

Apply gets its second argument (the array of array of movies) and calls the function (concat) as if each item in the array was an argument for the function.

So, you can use concat like that: [].concat([4], [5], [2, 3], ...), this is exactly what apply is doing, it’s calling each sub-array as if it was an argument.


#12

Thanks, this is very helpful.