Skip to content

unable to update hooks variable when fetching multiple urls in react

I am trying to store data from the TMDB movie api using a custom react hook .

useFetch.js

import {React,useState,useEffect} from 'react';


export default function useFetch() {

  const key = process.env.REACT_APP_API_KEY;
  
  //the urls I want to get data from     
  const specificTypes = [
    {'Type':'Top Rated', 'url' :`https://api.themoviedb.org/3/movie/top_rated?api_key=${key}`},
    {'Type':'Trending', 'url' :`https://api.themoviedb.org/3/trending/movie/day?api_key=${key}`},
  ];

 

  const [movieTypes,setMovieTypes] = useState([]); //this is where I want to store url data 

  useEffect(()=>{
    
    const fetchSpecificTypes = async ()=>{
      
       const promises = [];
       specificTypes.map(async type=>{
         let response = await fetch(type.url);
         let res = await response.json();
         promises.push(res.results);
       });
       console.log({promises}); data is stored in promises successfully
       setMovieTypes(promises); //how I try to set the movies 


    } 

    fetchSpecificTypes();

  },[]);

  return {movieTypes};

}

When I console.log({promises}) I get this object where the 2 items are the movie types with 20 movies inside : enter image description here And then when I try to display the movies from the object above in another component :

MovieList.js

    import {React , useState,useEffect} from 'react'
    import useFetch from './useFetch';
    import '../App.css';
    
    export default function MovieList() {
  
  const {movieTypes} = useFetch();
  const baseImgUrl = "https://image.tmdb.org/t/p";
  const size = "/w400";
  

  return (
    <div className="movie-list">
      {
        movieTypes.map(movie=>{
          return (
            <>
              {
                Object.values(movie).map((val,k)=>{
                    let path = baseImgUrl + size + val.backdrop_path; //full image path
                    return <div className= "movie-item" key = {val.id}>
                              <img alt = "movie" src = {path}/>
                              <h4 className="movie-overview"> {val.overview} </h4>
                              <p className="movie-title">{val.title}</p>
                    </div>
                })
              }
            </>
          )
        })  
      }
    </div>
  );
}

I get nothing no movies displayed . I would appreciate your help with this .

Answer

Await is not working as expected inside Array.map(). You should either use for loop or use Promise.all()

const fetchSpecificTypes = async() => {
  const promises = [];
  for(let i=0; i<specificTypes.length; i++) {
    let response = await fetch(specificTypes[i].url);
    let res = await response.json();
    promises.push(res.results);
  }
  setMovies(promises);
}

const fetchSpecificTypes = async() => {
  const results = await Promise.all(specificTypes.map(type => fetch(type.url)));
  const results2 = await Promise.all(results.map(res => res.json());
  const movies = results2.map(res => res.results);
  setMovies(movies);
}