0
votes

So I'm calling the tmdb API to get the movie details of the selected movie but that response does not contain the cast details like the actors so i use the id returned by the first response to call their other api to get the details of the cast.

This is the action


export const loadNewReleases = () => {
  const posterBaseUrl = "http://image.tmdb.org/t/p/w185";
  let hasUserSaved;
  return async (dispatch, getState) => {
    // console.log("????????", getState());
    try {
      const response = await fetch(
        `https://api.themoviedb.org/3/trending/all/day?api_key=${config.TMDB_API_KEY}`
      );

      if (!response.ok) {
        throw new Error("failed response");
      }

      const resData = await response.json();
      console.log(resData);

      const getCredits = async (index) => {
        let response, creditsData;
        try {
          response = await fetch(
            `https://api.themoviedb.org/3/movie/${resData.results[index].id}?api_key=${config.TMDB_API_KEY}&language=en-US&append_to_response=credits`
          );
          creditsData = await response.json();
          // console.log("credits", creditsData);
        } catch (err) {
          throw new Error(err);
        }

        const castMembers = [];
        const length = creditsData.credits.cast.length;

        for (let i = 0; i < length; i++) {
          castMembers.push(
            new Cast(
              creditsData.credits.cast[i].id,
              creditsData.credits.cast[i].character,
              creditsData.credits.cast[i].name,
              posterBaseUrl + creditsData.credits.cast[i].profile_path
            )
          );
        }

        console.log(castMembers);

        return castMembers;
      };

      const LoadedNewReleases = [];
      const length = resData.results.length;

      for (let i = 0; i < length; i++) {
        // let credits;
        hasUserSaved = getState().UserMovies.userMovies.find(
          (userMovie) => userMovie.id === resData.results[i].id.toString()
        );
        // let cast = getCredits(i).then((cast) => cast);
        // console.log("CAST", cast);
        LoadedNewReleases.push(
          new Movie(
            resData.results[i].id.toString(),
            resData.results[i].media_type === "movie"
              ? resData.results[i].title
              : resData.results[i].name,
            posterBaseUrl + resData.results[i].poster_path,
            resData.results[i].media_type === "movie"
              ? resData.results[i].release_date
              : resData.results[i].first_air_date,
            getCredits(i).then((cast) => cast),
            // cast,
            resData.results[i].overview,
            resData.results[i].vote_average,
            "",
            hasUserSaved ? hasUserSaved.location : ""
          )
        );
      }

      dispatch({ type: LOAD_NEW_RELEASES, new_releases: LoadedNewReleases });
    } catch (err) {
      console.log(err);
    }
  };
};

This is the reducer


switch(action.type){

    case LOAD_NEW_RELEASES:
      return {
        ...state,
        new_releases: action.new_releases,
      };

}

This is How I dispatch the action: selectedMovie.cast


     selectedMovie = movies.find((movie) => movie.id === selectedMovieId);
    console.log("selectedMovie", selectedMovie);

        <FlatList
          showsHorizontalScrollIndicator={false}
          horizontal={true}
          data={selectedMovie.cast}
          renderItem={(itemData) => (
            <CastMember
              castName={itemData.item.name}
              posterUrl={itemData.item.profileUrl}
              character={itemData.item.character}
            />
          )}
        />

This is the log

On Loading the app I get the following yellow warnings

[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'creditsData.credits.cast')] * store/actions/MoviesAction.js:77:25 in getCredits - node_modules/regenerator-runtime/runtime.js:45:44 in tryCatch - node_modules/regenerator-runtime/runtime.js:274:30 in invoke - node_modules/regenerator-runtime/runtime.js:45:44 in tryCatch - node_modules/regenerator-runtime/runtime.js:135:28 in invoke - node_modules/regenerator-runtime/runtime.js:145:19 in PromiseImpl.resolve.then$argument_0 - node_modules/promise/setimmediate/core.js:37:14 in tryCallOne - node_modules/promise/setimmediate/core.js:123:25 in setImmediate$argument_0 - node_modules/react-native/Libraries/Core/Timers/JSTimers.js:146:14 in _callTimer - node_modules/react-native/Libraries/Core/Timers/JSTimers.js:194:17 in _callImmediatesPass - node_modules/react-native/Libraries/Core/Timers/JSTimers.js:458:30 in callImmediates * [native code]:null in callImmediates - node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:407:6 in __callImmediates - node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:143:6 in __guard$argument_0 - node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:384:10 in __guard - node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:142:17 in __guard$argument_0 * [native code]:null in flushedQueue * [native code]:null in invokeCallbackAndReturnFlushedQueue

[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'creditsData.credits.cast')] * store/actions/MoviesAction.js:77:25 in getCredits - node_modules/regenerator-runtime/runtime.js:45:44 in tryCatch - node_modules/regenerator-runtime/runtime.js:274:30 in invoke - node_modules/regenerator-runtime/runtime.js:45:44 in tryCatch - node_modules/regenerator-runtime/runtime.js:135:28 in invoke - node_modules/regenerator-runtime/runtime.js:145:19 in PromiseImpl.resolve.then$argument_0 - node_modules/promise/setimmediate/core.js:37:14 in tryCallOne - node_modules/promise/setimmediate/core.js:123:25 in setImmediate$argument_0 - node_modules/react-native/Libraries/Core/Timers/JSTimers.js:146:14 in _callTimer - node_modules/react-native/Libraries/Core/Timers/JSTimers.js:194:17 in _callImmediatesPass - node_modules/react-native/Libraries/Core/Timers/JSTimers.js:458:30 in callImmediates * [native code]:null in callImmediates - node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:407:6 in __callImmediates - node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:143:6 in __guard$argument_0 - node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:384:10 in __guard - node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:142:17 in __guard$argument_0 * [native code]:null in flushedQueue * [native code]:null in invokeCallbackAndReturnFlushedQueue

and in dispatching the said action I get :

selectedMovie Movie {
  "cast": Promise {
    "_40": 0,
    "_55": Array [
      Cast {
        "character": "Tim Morris",
        "id": 60950,
        "name": "David Spade",
      },
      Cast {
        "character": "Missy",
        "id": 591834,
        "name": "Lauren Lapkus",
      },
      Cast {
        "character": "Camille",
        "id": 175585,
        "name": "Candace Smith",
      },
      Cast {
        "character": "Julia",
        "id": 49001,
        "name": "Sarah Chalke",
      },
      Cast {
        "character": "Melissa",
        "id": 60952,
        "name": "Molly Sims",
      },
      Cast {
        "character": "Jack Winstone",
        "id": 25879,
        "name": "Geoff Pierson",
      },
      Cast {
        "character": "Nate",
        "id": 32907,
        "name": "Nick Swardson",
      },
      Cast {
        "character": "Jess",
        "id": 60959,
        "name": "Jackie Sandler",
      },
      Cast {
        "character": "Rich",
        "id": 1573273,
        "name": "Chris Witaske",
      },
      Cast {
        "character": "Vanilla Ice",
        "id": 17338,
        "name": "Vanilla Ice",
      },
      Cast {
        "character": "Calvin Sr.",
        "id": 5621,
        "name": "John Farley",
      },
      Cast {
        "character": "Bus Woman",
        "id": 1922821,
        "name": "Lori Pelenise Tuisano",
      },
      Cast {
        "character": "Komante",
        "id": 60949,
        "name": "Rob Schneider",
      },
      Cast {
        "character": "Gary",
        "id": 1170011,
        "name": "Leati Joseph Anoa'i",
      },
      Cast {
        "character": "Toki Dum Dum",
        "id": 198149,
        "name": "Bobby Lee",
      },
    ],
    "_65": 1,
    "_72": null,
  },
  "id": "582596",
  "language": "",
  "location": "",
  "plot": "A guy meets the woman of his dreams and invites her to his company's corporate retreat, but realizes he sent the invite to the wrong person.",
  "posterUrl": "http://image.tmdb.org/t/p/w185/A2YlIrzypvhS3vTFMcDkG3xLvac.jpg",
  "ratings": 6.1,
  "title": "The Wrong Missy",
  "year": "2020-05-13",
}

See the cast object has a promise object and it has an array on _55 , that is the actual result. Also What is causing the yellow warnings they appear only when i perform the second api call.

Snack Link

Snack Link

when the app launches click on any of the items under trending> to see the log .

1
Make a snack of the issue on expo and link it with the question.Waheed Akhtar
added the link to the snack projectuser8212309

1 Answers

0
votes

Your issue is the line:

getCredits(i).then((cast) => cast)

You're not actually waiting for the result of this Promise, you're just passing in a Promise where a cast object should be.

You actually need to movie the creation of a Movie to the then call and then wait for all those to complete and unwrap them with await a Promise.all containing these new promises.

In the simplest way possible it'd be something like this:

const LoadedNewReleases = [];
const length = resData.results.length;

for (let i = 0; i < length; i++) {
  // let credits;
  hasUserSaved = getState().UserMovies.userMovies.find(
    (userMovie) => userMovie.id === resData.results[i].id.toString()
  );
  // let cast = getCredits(i).then((cast) => cast);
  // console.log("CAST", cast);
  LoadedNewReleases.push(
    getCredits(i).then(
      (cast) =>
        new Movie(
          resData.results[i].id.toString(),
          resData.results[i].media_type === "movie"
            ? resData.results[i].title
            : resData.results[i].name,
          posterBaseUrl + resData.results[i].poster_path,
          resData.results[i].media_type === "movie"
            ? resData.results[i].release_date
            : resData.results[i].first_air_date,
          cast,
          // cast,
          resData.results[i].overview,
          resData.results[i].vote_average,
          "",
          hasUserSaved ? hasUserSaved.location : ""
        )
    )
  );
}

dispatch({ type: LOAD_NEW_RELEASES, new_releases: await Promise.all(LoadedNewReleases) });

You may also want to move the hasUserSaved logic into there if you want that to run as late as possible, but I'm not quite sure what that's doing so have left it where it is.