【问题标题】:React - Fetch Data from API and map nested JSONReact - 从 API 获取数据并映射嵌套的 JSON
【发布时间】:2022-01-18 05:58:51
【问题描述】:

几天来,我正在尝试解决以下问题。当然,我已经研究并尝试了几种错误消息的解决方案,不幸的是它们都不起作用。我不知道我做错了什么,因此想问问你。 :)

错误消息: “TypeError:无法读取未定义的属性(正在读取'map')”

代码:


function App() {
  const [games, setGames] = useState();

  useEffect(() => {
    getGames();

    async function getGames() {
      const response = await fetch(
        "https://v3.football.api-sports.io/fixtures?season=2021&league=78&date=2021-12-04",
        {
          method: "GET",
          headers: {
            "x-rapidapi-host": "v3.football.api-sports.io",
            "x-apisports-key": "XXX",
          },
        }
      );

      const data = await response.json();
      setGames(data.parameters);
    }
  }, []);

  return (
    <div>
      <h1>Games</h1>
      <div className="games">
        {games.map((game, index) => (
          <div key={index}>
            <h2>{game.season}</h2>
          </div>
        ))}
      </div>
      )
    </div>
  );
}

export default App;

JSON: JSON GET EXAMPLE 稍后我想从 JSON 文件中提取团队。例如:response.teams.home.name

提前感谢您的关注! :) 如果有任何信息缺失,请告诉我。

问候和感谢

【问题讨论】:

  • 首先,不要公开分享您的私有 API 密钥。你的初始状态是空的,你可以创建一个类似 {games && games.map(xxx)} 的条件。
  • 我看到“参数”属性是一个对象,所以你不能在那里使用地图功能。如果你执行 setGames(data.response) 那么你可以使用 map 函数将你的状态变成一个列表。
  • 为什么不升级到 React 17+ 并利用函数组件?您已经在使用 useState 挂钩。
  • 现在已经在上述条件下尝试过了,不幸的是它也没有工作。但取而代之的是一条新的错误信息:TypeError: games.map is not a function 还删除了“参数”并使用 setGames(data.response) 进行了尝试。也没有成功。
  • 见下面的my response。你可以直接运行sn -p。只要您提供 API 密钥。

标签: reactjs json api


【解决方案1】:

如果您想适当地映射它,您需要了解数据的结构。

注意:不要将数组索引用于映射中项目的key。每个游戏都包含一个fixture 对象和一个id

const API_KEY = prompt('Supply the API key'); // Provide the key first!

const { useEffect, useState } = React;

const apiHost = 'v3.football.api-sports.io';
const apiUrl = `https://${apiHost}/fixtures`;
const apiKey = API_KEY;

const toParamString = (obj) => new URLSearchParams(obj).toString();

const getGames = ({ season, league, date }) => {
  const url = `${apiUrl}?${toParamString({ season, league, date })}`;
  return fetch(url, {
      method: 'GET',
      headers: {
        'x-rapidapi-host': 'v3.football.api-sports.io',
        'x-apisports-key': apiKey,
      },
    })
    .then(response => response.json())
    .then(data => data.response);
};

const Score = (props) => {
  const { game: { fixture: { date }, score: { fulltime }, teams } } = props;
  
  return (
    <div className="score">
      <div className="score-date">{new Date(date).toLocaleString()}</div>
      <div className="score-grid">
        <div>{teams.home.name}</div>
        <div>{teams.away.name}</div>
        <div>{fulltime.home}</div>
        <div>{fulltime.away}</div>
      </div>
    </div>
  );
};

const App  = () => {
  const [games, setGames] = useState([]);
  
  useEffect(() => {
    getGames({
      season: 2021,
      league: 78,
      date: '2021-12-04'
    }).then(data => setGames(data));
  }, []);
    
  return (
    <div>
      <h1 style={{ textAlign: 'center' }}>Games</h1>
      <div className="games">
        {games.map((game) => {
          const { fixture: { id } } = game;
          return (
            <Score key={id} game={game} />
          );
        })}
      </div>
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById('react-app'));
html, body {
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  display: flex;
  flex: 1;
}

#react-app {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex: 1;
}

.score {
  border: thin solid grey;
  margin: 0.667em;
  padding: 0.33em;
}

.score-date {
  display: flex;
  justify-content: center;
  font-weight: bold;
  font-size: larger;
  margin-bottom: 0.25em;
}

.score-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
}

.score-grid div {
  display: flex;
  justify-content: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react-app"></div>

【讨论】:

  • 有效! :) 非常感谢您将如此详细的代码放到网上!这非常有帮助!现在将研究代码以了解它是如何工作的。
【解决方案2】:

你可以试试这个吗?

 function App() {
      const [games, setGames] = useState({});
    
      useEffect(() => {
        getGames();
    
        async function getGames() {
          const response = await fetch(
            "https://v3.football.api-sports.io/fixtures?season=2021&league=78&date=2021-12-04",
            {
              method: "GET",
              headers: {
                "x-rapidapi-host": "v3.football.api-sports.io",
                "x-apisports-key": "3914b827d25c9a793d6af1ec9c312d55",
              },
            }
          );
    
          const data = await response.json();
          setGames(data.parameters);
        }
      }, []);
    
      return (
        <div>
          <h1>Games</h1>
          <div className="games">
            {Object.keys(games).length > 0 && games.map((game, index) => (
              <div key={index}>
                <h2>{game.season}</h2>
              </div>
            ))}
          </div>
          )
        </div>
      );
    }
    
    export default App;

【讨论】:

  • 'parameters' 键是一个对象,因此您无法通过它进行映射。请添加更多信息来解释您所做的修复。
  • 很遗憾,您的想法也没有奏效:/ 现在出现错误消息:TypeError: games.map is not a function
  • 我一直没有进行任何重大更改。总是尝试并失败 :D 例如,已经尝试一步一步地映射“游戏”以越来越深入。但是,总是出现错误消息。然后我在没有 .map() 的情况下尝试了它并收到以下错误消息:错误:对象作为 React 子项无效(找到:带有键 {} 的对象)。如果您打算渲染一组子项,请改用数组。由此我再次明白我必须通过 .map() 映射“游戏”。从那以后,我一直在兜圈子,找不到更多的解决方案。
猜你喜欢
  • 2021-08-05
  • 1970-01-01
  • 1970-01-01
  • 2022-11-13
  • 2020-02-12
  • 2013-12-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多