映射 Axios 响应并将第二个 Axios 响应附加到第一个

Map over Axios Response and append 2nd Axios Response to 1st

我正在使用 axios 和 TMDb API 创建电影搜索 React 应用程序。我想进行 axios.get 调用以根据 query 搜索电影,然后映射响应,并将每部电影的 movie.id 传递到第二个 axios 调用获取每部电影的更多详细信息。

我尝试了很多方法,但我对如何 return 这些值感到困惑,或者我是否需要在代码中的某个时刻使用 async/await 来等待响应.我真的不知道解决这个问题的最佳方法 - 必须有一个简单的方法来按顺序进行,但问题的异步性质使我很难做到这一点。

我认为在我的搜索函数中进行第一个 axios 调用会更简单,然后编写第二个函数 getDetails(id) 获取电影 ID 并使用它进行 axios 调用。

理想情况下,如果我在地图中调用 getDetails 函数,获得响应,将该响应附加到我的电影数组,我可以轻松地拥有一个电影数组,每个电影都附加了详细信息。然后我可以将整个数组存储在状态中,并使用单个状态来管理我所有的电影数据。我知道这个过程不是同步的,而且 axios 是基于承诺的,但是有没有办法按顺序处理这个问题,或者我是不是完全错了?我知道 .push() 在这种情况下不起作用,但我尝试了其他方法,它们总是 return 未定义、承诺或意外结果。

 const search = query => {
    axios
      .get(
        `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&language=en-US&query=${query}&page=1&include_adult=false`
      )
      .then(response => {
        response.data.results.map(movie => {
          const details = getDetails(movie.id);
          return movie.push(details);
        });
      });
  };

  const getDetails = id => {
    axios
      .get(
        `https://api.themoviedb.org/3/movie/${id}?api_key=${API_KEY}&language=en-US`
      )
      .then(response => {
        return response.data;
      });
  };

编辑 1: 我玩过 Abanoub Istfanous 的答案,它似乎 return undefined 添加了调度来更新我的状态。我对其进行了更多调整,第二组标记为 WORKING 的代码似乎正在显示一些搜索结果,但我无法将 getDetails 中的任何附加数据呈现到屏幕上,因为它们显示为未定义。我还是做错了什么吗?

不工作:

  const search = async query => {
    dispatch({
      type: MOVIE_SEARCH_REQUEST
    });
    const response = await axios.get(
      `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&language=en-US&query=${query}&page=1&include_adult=false`
    );

    const data = Promise.all(
      response.data.results.map(async movie => {
        movie.details = await getDetails(movie.id);
      })
    );

    dispatch({
      type: MOVIE_SEARCH_COMPLETE,
      payload: data
    });
    return data;
  };

// getDetails is unchanged...

正在工作:


  const search = async query => {
    dispatch({
      type: MOVIE_SEARCH_REQUEST
    });
    const response = await axios.get(
      `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&language=en-US&query=${query}&page=1&include_adult=false`
    );

    const data = Promise.all(
      response.data.results.map(async movie => {
        movie.details = await getDetails(movie.id);
      })
    );

    dispatch({
      type: MOVIE_SEARCH_COMPLETE,
      payload: response.data.results
    });
    return data;
  };

// getDetails is unchanged...

我推荐使用 Promise

/*
*@return data 
*/
const getDetails = async (id) => {
    const response =  await axios
      .get(
        `https://api.themoviedb.org/3/movie/${id}?api_key=${API_KEY}&language=en-US`
      )
      return response.data
  };


然后

 const search = async (query) => {
    const response = await axios
      .get(
        `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&language=en-US&query=${query}&page=1&include_adult=false`
      );
const data = Promise.all(response.data.results.map(async movie => {

  movie.details = await getDetails(movie.id);
}))
return data

  };


之所以 return 未定义是因为 Promise.all() 将在作业队列上异步执行,并且最终只会 return 结果 Javascript被执行并且调用堆栈变空。因此,您的代码的一个简单解决方案是在 Promise.all().

之前放置一个 await
const search = async query => {
dispatch({
  type: MOVIE_SEARCH_REQUEST
});
const response = await axios.get(
  `https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&language=en-US&query=${query}&page=1&include_adult=false`
);

const data = await Promise.all(
  response.data.results.map(async movie => {
    movie.details = await getDetails(movie.id);
  })
);

dispatch({
  type: MOVIE_SEARCH_COMPLETE,
  payload: response.data.results
});
return data; //No need to return data since you are dispatching it to redux store
};

您可以在此处阅读有关 JS 在浏览器上的异步特性的更多信息:

https://medium.com/@Rahulx1/understanding-event-loop-call-stack-event-job-queue-in-javascript-63dcd2c71ecd