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

React/JavaScript嵌套API调用:map()内二次请求数据异常问题

问题原因

你当前所有电影卡片共用同一个movieInfo全局状态,无论触发哪部电影的详情请求,返回的数据都会覆盖这个唯一的状态值;列表渲染时所有卡片读取的都是这同一个状态值,自然会全部显示同一份详情。
不建议在map遍历过程中直接批量发起详情请求,会产生不必要的请求风暴,拖慢页面加载速度,按需点击加载是更合理的实现方式

修复步骤
  1. 把原本存单个详情的movieInfo状态,改为以电影imdbID为键的对象结构,用来存储所有已经加载过的电影详情,不同电影的详情数据互不干扰
  2. 调整详情请求逻辑,拿到单部电影详情后,把数据存入上述对象对应的ID键下
  3. 列表渲染时,每部电影只读取自身ID对应的详情数据展示,不再全局共用同一份数据
  4. 可选优化:增加加载状态判断,已经加载过详情的电影不再重复发请求
修改后完整代码
import { useState } from "react";

const Home = () => {
  const key = 'eee0805f';
  const baseUrl = 'https://www.omdbapi.com/?apikey=' + key;
 
  // 搜索输入相关状态
  const [message, setMessage] = useState('');
  const [searchTerm , setSearchTerm] = useState('');
  const [movies, setMovies] = useState(null);
  // 修改:用对象存储所有已加载的电影详情,key为imdbID,value为对应详情
  const [movieInfoMap, setMovieInfoMap] = useState({});
  // 存加载中的电影ID,做loading提示
  const [loadingId, setLoadingId] = useState(null);

  const handleChange = event => {
    setMessage(event.target.value);
  };

  const fetchData = async (url) => {
    try {
        const response = await fetch(url);
        const json = await response.json();
        setMovies(json.Search);
        // 每次新搜索清空之前的详情缓存
        setMovieInfoMap({});
    } catch (error) {
        console.log("error", error);
    }
  };

  const fetchMovieInfo = async (url, movieId) => {
    // 如果已经加载过该电影详情,直接返回不重复请求
    if (movieInfoMap[movieId]) return;
    setLoadingId(movieId);
    try {
        const response = await fetch(url);
        const json = await response.json();
        // 把新拿到的详情存入map,保留之前其他电影的详情数据
        setMovieInfoMap(prev => ({
          ...prev,
          [movieId]: json
        }));
    } catch (error) {
        console.log("error", error);
    } finally {
      setLoadingId(null);
    }
  };

  const searchMovie = () => {
    let url = baseUrl + '&s=' + encodeURIComponent(message);
    fetchData(url);
    setSearchTerm(message);
    setMessage("");
  }

  const moreInfo = (e, movieId) => {
    let url = baseUrl + '&i=' + movieId;
    fetchMovieInfo(url, movieId);
  }

  return (
    <div className="home">
      <div className="searchContainer">
        <input type="text" id="message" name="message" onChange={handleChange} value={message} placeholder="Please Enter Movie" />
        <span style={{ 
          color: 'white', 
          backgroundColor: '#f1356d',
          borderRadius: '8px' ,
          padding: '2px 8px',
          cursor: 'pointer'
        }} onClick={searchMovie}>Search</span>
      </div>

      <h3>Title Searched: {searchTerm}</h3>

      {movies && <div>
        {movies.map(movie => {
          // 取当前电影对应的详情
          const currentMovieInfo = movieInfoMap[movie.imdbID];
          return (
          <div className="movie-preview" key={movie.imdbID} >
            <div className="movie-content">
              <div className="movie-premier-image-content">
                <img className="movie-preview-image" src={movie.Poster} alt={movie.Title} />
              </div>
              <div>
                <h2 className="movie-preview-headline">{ movie.Title }</h2>
                <p>{movie.Year}</p>

                  {/* 只渲染当前电影对应的详情 */}
                  {currentMovieInfo && <div>
                    <p>Director(s): {currentMovieInfo.Director}</p>
                    <p>Genre: { currentMovieInfo.Genre }</p>
                    <p>Date released: {currentMovieInfo.Released}</p>
                  </div>}

                  {loadingId === movie.imdbID && <p>加载详情中...</p>}
              </div>
            </div>

            <div style={{ 
              color: 'white', 
              backgroundColor: '#f1356d',
              borderRadius: '8px' ,
              padding: '2px 8px',
              height: '24px',
              width: '75px',
              cursor: 'pointer'
              }} onClick={(e) => moreInfo(e, movie.imdbID)}>More Info</div>
          </div>
        )})}
      </div>}
    </div>
  );
}
 
export default Home;
改动说明
  • 去掉了从DOM上取data-key的写法,直接在点击回调里传入当前电影的ID,更符合React数据驱动的写法
  • 每次发起新的搜索时会清空之前缓存的详情数据,避免新旧搜索结果数据混淆
  • 增加了重复请求判断,已经加载过详情的电影不会重复发起接口请求
  • 增加了简单的加载提示,交互更友好

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:39:17