You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何顺序发起多个fetch请求获取OMDB API全部分页数据

问题原因

你的代码异常和await等待逻辑无关,核心是两个低级错误:

  • 外层声明的let movies没有设置初始值,默认是undefined
  • 循环内部用const重新声明了同名movies变量,这个变量是循环块级作用域,仅在当前轮次生效,完全不会修改外层的movies,所以循环结束后外层变量还是undefined,自然会出现赋值为空、loading提前关闭的现象。

另外你的循环从page=1开始,会重复请求第一页数据,浪费请求额度。

正确实现

OMDB接口必须先拿到第一页返回的totalResults才能计算总页数,不需要单独发一次请求查总页数,第一页的返回数据可以直接复用,减少冗余请求。

方案1:顺序请求(推荐,避免触发免费版接口限流)

按页码顺序逐次请求,对接口压力小,不会触发频率限制:

const [loading, setLoading] = useState(true);
const [data, setData] = useState([]);

const fetchMovies = async () => {
  setLoading(true);
  const baseUrl = `http://www.omdbapi.com/?apikey=${API_KEY}&s=${searchResult}`;

  try {
    // 请求第一页数据,同时拿到总结果数
    const firstResp = await fetch(baseUrl);
    const firstData = await firstResp.json();
    // 初始化结果数组,直接存入第一页数据
    let movies = firstData.Search ?? [];
    const totalPages = Math.ceil(Number(firstData.totalResults) / 10);

    // 从第二页开始循环请求,避免重复请求第一页
    for (let page = 2; page <= totalPages; page++) {
      const pageResp = await fetch(`${baseUrl}&page=${page}`);
      const pageData = await pageResp.json();
      // 直接修改外层的movies变量,不要重新声明同名变量
      movies = [...movies, ...(pageData.Search ?? [])];
    }

    // 所有请求执行完成后才会走到这里,统一更新数据
    setData(movies);
  } catch (error) {
    console.log('请求失败:', error);
  } finally {
    // 无论成功失败都关闭loading,避免页面一直处于加载状态
    setLoading(false);
  }
};

useEffect(() => {
  fetchMovies();
}, [searchResult]); // 将搜索关键词加入依赖,关键词变化时自动重新拉取

注意:for循环内部的await本身就会等待上一个请求resolve后才会执行下一轮,不需要额外做等待控制,只要变量作用域正确,一定会等所有请求完成才会执行循环后的逻辑。

方案2:并发请求(拉取速度快,适合总页数少的场景)

如果总页数不多,可以一次性构造所有分页请求,用Promise.all等待所有请求完成后合并结果,拉取速度更快:

const fetchMoviesParallel = async () => {
  setLoading(true);
  const baseUrl = `http://www.omdbapi.com/?apikey=${API_KEY}&s=${searchResult}`;
  try {
    const firstResp = await fetch(baseUrl);
    const firstData = await firstResp.json();
    const totalPages = Math.ceil(Number(firstData.totalResults) / 10);

    // 构造剩余所有分页的请求Promise
    const pageRequests = [];
    for (let page = 2; page <= totalPages; page++) {
      pageRequests.push(
        fetch(`${baseUrl}&page=${page}`).then(res => res.json())
      );
    }

    // 等待所有分页请求完成
    const allPageResult = await Promise.all(pageRequests);
    // 合并所有页的结果
    const movies = allPageResult.reduce(
      (res, current) => [...res, ...(current.Search ?? [])],
      firstData.Search ?? []
    );

    setData(movies);
  } catch (error) {
    console.log('请求失败:', error);
  } finally {
    setLoading(false);
  }
};

注意:OMDB免费版API有严格的请求频率限制,总页数超过5页时不建议用并发方案,很容易触发限流返回401/429错误。

疑问说明
  • 不需要单独写逻辑先获取总页数再发请求:第一次请求第一页数据时已经能拿到totalResults字段,直接复用这个返回值即可,多一次单独请求只会浪费接口额度。
  • 不可能在首次请求内完成全量拉取:接口单次最多返回10条,必须分页请求,没有参数可以一次性拉回所有结果。

内容的提问来源于stack exchange,提问作者Olivier Moreau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:27:40