Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

160
Vistas
How to set state of an Array of objects using useState?

I'm building a movies app in React and I'm using TMDB's api for that. I'm completely new to functional components and have a few queries. First I fetch all the genres using an api, and then iterate the genres one by one and call another API for fetching 20 movies in that genre.

The final data should look like this:

[{
    genre: 'action',
    movies: [],
},
{
    genre: 'adventure',
    movies: [],
}]

So that I can iterate the above array of objects and display the genre and its corresponding movies.

Right now, I'm stuck with the below code.

const [movieData, setMovieData] = useState([]);

const fetchGenres = async () => {

    const url = `https://api.themoviedb.org/3/genre/movie/list?api_key=xxx&language=en-US`;
    
    try {
      const res = await fetch(url);
      const data = await res.json();
      setMovieData(data.genres);      
    } catch (err) {
      console.error(err);
    }
}

Now, coming to the queries,

  1. Right now, movieData is an array and consists of only genres. How to a add movies too and change it to an array of objects ?
  2. How to iterate the genres and set corresponding movies in movieData?
  3. Any other easy/efficient way of doing this?

Solutions are much appreciated!

about 4 years ago · Juan Pablo Isaza
3 Respuestas
Responde la pregunta

0

To my mind it's better to keep your data separately. I mean array of genres and array of movies. So you will have:

const [genres, setGenres] = useState([]);
const [movies, setMovies] = useState([]);

then you make your async call to fetch genres and set it to state:

const fetchGenres = async () => {
    const url = `https://baseurl/3/genre/movie/list?api_key=token&language=en-US`;

    try {
        const res = await fetch(url);
        const data = await res.json();
        setGenres(data.genres);
    } catch (err) {
        console.error(err);
    }
};


React.useEffect(()=>{
    fetchGenres();
},[]);

to find out that the genres were set you can create an effect, that will update each time when genres change:

async function fetchMovies() {
    let result = [];

    for (const genre of genres) {
        const url = `https://baseurl/3/discover/movie?api_key=token&with_genres=${genre.id}`;
        const res = await fetch(url);
        const { results } = await res.json();

        result = [...result, ...results];
    }

    setMovies(result);
}

React.useEffect(() => {
    fetchMovies();
}, [genres]);

and finally we can use React.useMemo to calculate the result array we need according to genres and movies, it will be recalculated each time when one of the inner params change:

const resultArray = React.useMemo(() => {
    return genres.map(genre => ({
        genre,
        movies: movies.filter((movie) => movie.genre_ids.includes(genre.id))
    }));
}, [genres, movies])

I believe you will get an array like this

[{
    genre: 'action',
    movies: [],
},
{
    genre: 'adventure',
    movies: [],
}]
about 4 years ago · Juan Pablo Isaza Denunciar

0

As you already said, you first need to fetch the array of genres. Then you must iterate over this array and create a list of promises to fetch the corresponding movies. Once theses promises have been resolved (using Promise.all function) you can update the state variable movieData.

const GENRE_URL = `https://.../genre/movie/list?api_key=xxx&language=en-US`;

const MOVIE_URL = `https://.../movie/list?api_key=xxx&language=en-US&genre=`;

async function fetchGenres() {
  try {
    const genres = await fetch(GENRE_URL).then(res => res.json());

    const moviePromises = genres.map(genre => {
      return fetch(MOVIE_URL + genre)
        .then(res => res.json())
        // build an object containing 2 keys `genre` and `movies`
        .then(movies => ({genre, movies})); 
    });

    return await Promise.all(moviePromises);  
  } catch (err) {
    console.error(err);
    throw err;
  }
}

you must adapt the MOVIE_URL to your needs, I don"t really know what the real url is, I imagine you need to pass the genre value as a path param or a query param.

you can now call this function in the useEffect hook to load the movies when the component is rendered.

function App() {
  const [movieData, setMovieData] = useState([]);

  useEffect(() => {
    fetchMoviesGroupByGenre()
      .then(data => setMovieData(data))
      .catch(...);
  }, []);

  return ...
}

In term of performance, you will not display anything before all the movies have been fetched.

If it's a problem for you, you can update the state variable as soon as the api gives you an answer

async function fetchGenres() {
  try {
    const genres = await fetch(GENRE_URL).then(res => res.json());
    
    const moviePromises = genres.map(genre => {
      return fetch(MOVIE_URL + genre)
        .then(res => res.json())
        .then(movies => {
          const item = {genre, movies};
          setMovieData(prevMovieData => [...prevMovieData, item]);
          return item;
        ]);
    });

    return await Promise.all(moviePromises);  
  } catch (err) {
    console.error(err);
    throw err;
  }
}
about 4 years ago · Juan Pablo Isaza Denunciar

0

From what I understood what you want to do is

setMovieData(prevMovieData => ([
...prevMovieData,
{ genre: genreFromApiCall, movies: moviesFromApiCall }
])
)
about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda