简体   繁体   中英

How to assign an Ajax response to a variable in another function in React?

I have an ajax call that responds with a list of movies, and then I have an other function with an other ajax call that returns the genre names, since the first call only has the id of the genre, then I relate the genreId with its name and I assign it to the JSON on the first ajax call, kind of like assigning it to a variable. The problem that I have is that since ajax is asynchronous, it always ends up undefined. I don't want to make it synchronous since it will end up in a bad user experience.

First ajax call

$.ajax({
        url: urlString,
        success: (searchResults) => {
            const results = searchResults.results

            var movieRows = [];

            results.forEach(movie => {
                movie.genres = this.getMovieGenres(movie.media_type, movie.genre_ids);

                const movieRow = <MovieRow key={movie.id} movie={movie}/>;
                movieRows.push(movieRow)
            });

            this.setState({rows: movieRows})

        },
        error: (xhr, status, err) => {
            console.log("Failed to fetch data...")
        }
    })

Function that I call with the second ajax call

getMovieGenres (mediaType ,movieGenreIds) {

    urlString = `https://api.themoviedb.org/3/genre/movie/list?api_key=${config.movieDBbApiKey}&language=en-US`ApiKey}&language=en-US`

    var genres = []

    $.ajax({
        url: urlString,
        async: true,
        crossDomain: true,
        method: "GET",
        success: searchResults => {
          for (let i = 0; i < movieGenreIds.length; i++) {
            for (let j = 0; j < searchResults.genres.length; i++){
              console.log(searchResults.genres[j].id)
              if (movieGenreIds[i] === searchResults.genres[j].id) {
                genres.push(searchResults.genres[j].name)
              }
            }
          }

        },
        error: (xhr, status, err) => {
            console.log("Failed to fetch data...")
        }
    })

  return genres

}

There are variouse solutions to your problem.

The simplest is to make the second ajax call in the callback of the first ajax call . In the second call you'll have both results from first ajax call and the second . Then make transforms and set state in the second call.

Other options (the reccomended one) is to work with Axios or Fetch that rely on Promises. Promises can be evaded with Promise.all:

 var p1 = Promise.resolve(3); var p2 = 1337; var p3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, "foo"); }); Promise.all([p1, p2, p3]).then(values => { console.log(values); // [3, 1337, "foo"] });

you can try this:

var promise = new Promise((resolve,reject)=> {
    return $.ajax({
        url: urlString,
        success: (searchResults) => {
            return resolve(searchResults.results)

        },
        error: (xhr, status, err) => {
            return reject("Failed to fetch data...")
        }
    })
})

function that return a promise

getMovieGenres (mediaType ,movieGenreIds) {

    urlString = `https://api.themoviedb.org/3/genre/movie/list?api_key=${config.movieDBbApiKey}&language=en-US`ApiKey}&language=en-US`

    var genres = []

    return new Promise((resolve,reject)=> {
        $.ajax({
            url: urlString,
            async: true,
            crossDomain: true,
            method: "GET",
            success: searchResults => {
                for (let i = 0; i < movieGenreIds.length; i++) {
                    for (let j = 0; j < searchResults.genres.length; i++){
                        console.log(searchResults.genres[j].id)
                        if (movieGenreIds[i] === searchResults.genres[j].id) {
                            genres.push(searchResults.genres[j].name)
                        }
                    }
                }

                return resolve(genres)

            },
            error: (xhr, status, err) => {
                return reject("Failed to fetch data...")
            }
        })
    }) 
}

finally:

promise().then(results => {

    var movieRows = [];
    var tasks = []

    results.forEach(movie => {
        tasks.push(getMovieGenres(movie.media_type, movie.genre_ids))
    });

    Promise.all(tasks).then(output => {
        output.forEach(movie => {
            const movieRow = <MovieRow key={movie.id} movie={movie}/>;
            movieRows.push(movieRow)
        })

        this.setState({rows: movieRows})
    })
})

Hope to help you!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM