Search code examples
reactjsreact-reduxredux-toolkit

How can I get all genres from tmdb api using redux tool kit


const initialState = {
  Most_Popular: [], // List Movies Popular Shown on home page
  top_rated: [], // List top_rated Shown on home page
  Movies: [], // All movies list
  Movie: {}, // current Movie
  isLoading: true, // cheak if page is loading
  isError: false,
};
export const getMoviesGenres = createAsyncThunk(
  "getMoviesGenres",
  async (_, thunkAPI) => {
    try {
      const api = `api_key=${process.env.REACT_APP_KEY_API}`;
      const data = await getJSON.get(`genre/movie/list?${api}`); // get all id genres

      for (let i = 0; i <= data.data.genres.length; i++) {
        if (!data.data.genres[i]) return; // guard clauses
        const { id, name } = data.data.genres[i];

        const dataMovieGenres = [
          await getJSON.get(`discover/movie?${api}&with_genres=${id}`)
        ];
        return dataMovieGenres;
      }
    } catch (error) {
      return thunkAPI.rejectWithValue(error);
    }
  }
);
    // get Movies Genres
    builder
      .addCase(getMoviesGenres.pending, (state) => {
        state.isLoading = true;
        state.isError = false;
      })
      .addCase(getMoviesGenres.fulfilled, (state, { payload }) => {
        console.log(payload);
        // state.Movies = payload.data.results;
        state.isLoading = false;
        state.isError = false;
      })
      .addCase(getMoviesGenres.rejected, (state, { payload }) => {
        state.isLoading = false;
        state.isError = false;
        toast.error(payload.message);
      });

Hi, I am trying to get all movies from all genres from tmdb api using redux tool kit.

I made a for loop that will make an api call until there are no more movies. After that I want to put all the movies into the Movies array.

I'm having a problem that I can't for some reason I only get genre 1 from the loop.

Again my goal is that dataMovieGenres Bring me all the movies you have and then I can handle my data in extraReducers Then of course iterate on them and display all the movies from all the categories I have.

like I mentioned I only get one genre.

I need some way to get any data from axios and transfer it to an array and then perform a return. The problem is that I don't want to use push because of a side effect.

enter image description here


Solution

  • Promises can only be fulfilled once. You are seeing the getMoviesGenres resolve after the first "inner"/nested-loop request resolves, the rest are ignored since the action was already fulfilled.

    You'll want to create an array of Promises for all genres' movies that can be awaited en masse.

    Example:

    export const getMoviesGenres = createAsyncThunk(
      "getMoviesGenres",
      async (_, thunkAPI) => {
        try {
          const api = `api_key=${process.env.REACT_APP_KEY_API}`;
          const { data } = await getJSON.get(`genre/movie/list?${api}`);
    
          const moviesReqs = data.genres.map(async ({ id }) => {
            const { data } = getJSON.get(`discover/movie?${api}&with_genres=${id}`);
            return data.results; // array of movies in genre
          });
    
          const movies = await Promise.all(moviesReqs)
            .then(allMovies => allMovies.flat()); // flatten array of array of movies
    
          return movies;
        } catch (error) {
          toast.error(error.message); // <-- toast from here, reducer is pure
          return thunkAPI.rejectWithValue(error);
        }
      }
    );
    
    // get Movies Genres
    builder
      .addCase(getMoviesGenres.pending, (state) => {
        state.isLoading = true;
        state.isError = false;
      })
      .addCase(getMoviesGenres.fulfilled, (state, { payload }) => {
        console.log(payload);
        state.movies = payload; // <-- save payload into state
        state.isLoading = false;
        state.isError = false;
      })
      .addCase(getMoviesGenres.rejected, (state, { payload }) => {
        state.isLoading = false;
        state.isError = true;
      });