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

使用Axios多GET请求时React setState仅添加最后一条剧集数据问题

问题描述

我尝试通过Rick and Morty API获取并列出选中角色出场的所有剧集,但角色的episode属性返回的是URL列表,因此我通过循环来获取这些剧集详情。

问题在于,请求发起后,console.log能打印所有剧集对象,但setState钩子的setEpisodes仅添加最后一条剧集。我尝试过其他循环方式,但结果始终相同。期望所有剧集都能被列出,但实际仅显示最后一条。

相关代码

http.js

import axios from "axios";

const http = axios.create({
  baseURL: "https://rickandmortyapi.com/api/",
  timeout: 10000,
});

export default http;

character-details 组件

import { useEffect, useState } from "react";
import http from "../../utils/http";

const CharacterDetails = () => {
  const [character, setCharacter] = useState(null);
  const [episodes, setEpisodes] = useState([]);

  useEffect(() => {
    http.get('/character/1').then((response) => {
      setCharacter(response.data);
    });
  }, []);

  useEffect(() => {
    if (character) {
      character.episode.map((episodeUrl) => {
        const episodeId = getEpisodeIdFromEpisodeURL(episodeUrl);

        http.get(`/episode/${episodeId}`).then((response) => {
          console.log(response.data);
          setEpisodes([...episodes, response.data]);
        });
      });
    }
  }, [character]);

  function getEpisodeIdFromEpisodeURL(episode) {
    const lastIndex = episode.lastIndexOf("/");
    const episodeId = episode.slice(lastIndex + 1);
    return episodeId;
  }

  return (
    <>
      {character && (
        <>
          <div>
            <img src={character.image} alt="Character photo" />
            <h3>{character.name}</h3>
          </div>
          <p>{character.status}</p>
          <p>{character.species}</p>
          <p>{character.location.name}</p>
          {episodes.map((episode) => {
            return <p key={episode.id}>Episode: {episode.name}</p>;
          })}
        </>
      )}
    </>
  );
};

export default CharacterDetails;
解决方案

问题原因

问题出在React状态更新的闭包特性上:当你在循环里调用setEpisodes([...episodes, response.data])时,每次调用的episodes都是组件初始渲染时的空数组(因为useEffect的依赖是character,整个循环在character变化时执行一次,所有请求的回调里捕获的episodes都是同一个初始值)。所以每次更新都是把新数据加到空数组里,最终只会保留最后一次请求的结果。

解决方法1:使用函数式更新

把setEpisodes改成函数式更新,这样每次都会基于最新的状态来更新:

http.get(`/episode/${episodeId}`).then((response) => {
  console.log(response.data);
  setEpisodes(prevEpisodes => [...prevEpisodes, response.data]);
});

解决方法2:一次性批量获取(更高效)

Rick and Morty API支持批量获取剧集,你可以把所有剧集ID拼接成一个请求,减少HTTP请求次数:

useEffect(() => {
  if (character) {
    // 提取所有剧集ID并用逗号拼接
    const episodeIds = character.episode.map(url => url.split('/').pop()).join(',');
    http.get(`/episode/${episodeIds}`).then((response) => {
      // 批量请求返回的是数组,直接设置状态
      setEpisodes(response.data);
    });
  }
}, [character]);

这种方式不仅解决了状态更新的问题,还大幅减少了请求数量,性能更好。

内容的提问来源于stack exchange,提问作者Lucas Macêdo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:29:58