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

React Hook组件API调用前渲染问题及宝可梦应用开发咨询

解决React PokeAPI应用的Props传递错误与数据请求疑问

首先,咱们先搞定你遇到的props.map is not a function错误——这个问题完全是props传递和解构的细节没处理对,具体来说有这几个核心问题:

错误根源解析

  1. App.js里的Pokemons组件接收props方式错误
    你定义的function Pokemons(pokemons) {其实是把整个props对象当成了pokemons参数,但React组件的参数本身就是一个包含所有传入属性的对象,正确的做法是解构出pokemons属性:

    function Pokemons({ pokemons }) { // 解构props里的pokemons属性
      return <PokemonList pokemons={pokemons} />; // 正确传递数组,而非整个props对象
    }
    

    你之前写的<PokemonList props={pokemons} />会把数组直接赋值给props属性,导致PokemonList里拿到的props.props才是目标数组,这显然不符合预期。

  2. PokemonList组件调用map的对象错误
    你的PokemonList组件里写的是props.map,但这里的props是组件接收的属性对象,真正的数组是props.pokemons,所以应该改成:

    {props.pokemons.map(function (object, i) { ... })}
    

    或者直接解构props让代码更清晰:

    const Pokemonlist = ({ pokemons }) => {
      let content = (
        <Card.Group>
          {pokemons.map(function (object, i) {
            return <PokeCard pokemon={object} key={i} />;
          })}
        </Card.Group>
      );
      return content;
    };
    
  3. PokeCard组件的props解构问题
    同样,PokeCard的参数是props对象,你需要解构出pokemon属性,而且注意PokeAPI返回的results数组里只有name和url,没有img、base_experience、id,这些需要后续通过url请求详情获取,现在先修正解构:

    const PokeCard = ({ pokemon }) => {
      // 暂时先显示name,后续可通过pokemon.url请求详情
      let content = (
        <Card>
          <Card.Content>
            <Card.Header>{pokemon.name}</Card.Header>
            <Card.Description>详情地址: {pokemon.url}</Card.Description>
          </Card.Content>
        </Card>
      );
      return content;
    };
    
  4. Types组件未触发数据请求
    你的Types组件里没有调用getTypes,所以点击Types链接时不会获取类型数据,这个后续可以用useEffect来处理。


你的三个疑问解答

1. 我遗漏了什么?

除了上面说的props传递和解构错误,还有这些细节:

  • 重复引入axios:App.js顶部已经import axios from "axios";,但getPokemons和getTypes里又重复用require引入,完全没必要,直接用顶部导入的axios即可。
  • 数据请求触发时机不合理:把getPokemons绑定在Link的onClick上,刷新/pokemons页面时数据会丢失,因为onClick不会在页面刷新时触发。
  • 未处理加载状态:虽然定义了isLoading,但组件里没根据这个状态显示加载提示,用户看不到等待过程。

2. 当前场景是否需要使用useEffect?

非常需要!useEffect是Hook中处理副作用(比如数据请求)的核心API,你的场景下:

  • 当用户进入/pokemons或/types路由时,应该自动触发数据请求,而非依赖Link的onClick。
  • 用useEffect可以在组件挂载(或路由匹配)时自动执行请求,刷新页面也能重新获取数据,完全符合React的组件生命周期逻辑。

3. 数据请求的时机与位置应如何选择?

推荐在需要使用数据的子组件(路由组件)中发起请求,而非在App组件里统一请求:

  • 比如Pokemons组件负责展示宝可梦列表,就由它来调用请求获取数据,这样组件的职责更单一,数据和视图绑定更紧密。
  • 请求时机:在组件挂载时(useEffect的依赖数组为空[])发起请求,若有分页等需求,可在路由参数变化时重新请求。

修正后的完整代码

App.js

import React from "react";
import "./App.css";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";

const App = () => {
  // 把状态移到对应的路由组件,让组件自主管理数据
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/pokemons">Pokemons</Link>
            </li>
            <li>
              <Link to="/types">Types</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/pokemons">
            <Pokemons />
          </Route>
          <Route path="/types">
            <Types />
          </Route>
        </Switch>
      </div>
    </Router>
  );
};

// Pokemons组件:自主管理状态与请求逻辑
function Pokemons() {
  const [pokemons, setPokemons] = React.useState([]);
  const [isLoading, setIsLoading] = React.useState(true);
  const axios = require("axios").default;

  const getPokemons = async () => {
    try {
      const response = await axios.get("https://pokeapi.co/api/v2/pokemon");
      setPokemons(response.data.results);
    } catch (err) {
      console.error("获取宝可梦数据失败:", err);
    } finally {
      setIsLoading(false);
    }
  };

  // 组件挂载时发起请求
  React.useEffect(() => {
    getPokemons();
  }, []);

  if (isLoading) {
    return <div>加载中...</div>;
  }

  return <PokemonList pokemons={pokemons} />;
}

// Types组件:同理实现自主数据管理
function Types() {
  const [types, setTypes] = React.useState([]);
  const [isLoading, setIsLoading] = React.useState(true);
  const axios = require("axios").default;

  const getTypes = async () => {
    try {
      const response = await axios.get("https://pokeapi.co/api/v2/type");
      setTypes(response.data.results);
    } catch (err) {
      console.error("获取类型数据失败:", err);
    } finally {
      setIsLoading(false);
    }
  };

  React.useEffect(() => {
    getTypes();
  }, []);

  if (isLoading) {
    return <div>加载中...</div>;
  }

  return (
    <div>
      <h2>TYPES:</h2>
      <ul>
        {types.map((type, i) => (
          <li key={i}>{type.name}</li>
        ))}
      </ul>
    </div>
  );
}

// 导入组件要放在使用前
import PokemonList from "./components/PokemonList";
export default App;

PokemonList.js

import React from "react";
import { Card } from "semantic-ui-react";
import PokeCard from "./PokeCard";

const Pokemonlist = ({ pokemons }) => {
  return (
    <Card.Group>
      {pokemons.map((pokemon, i) => (
        <PokeCard pokemon={pokemon} key={i} />
      ))}
    </Card.Group>
  );
};

export default Pokemonlist;

PokeCard.js

import { Card } from "semantic-ui-react";
import React from "react";

const PokeCard = ({ pokemon }) => {
  // 若要获取宝可梦头像、ID等详情,可在此用useEffect请求pokemon.url
  return (
    <Card>
      <Card.Content>
        <Card.Header>{pokemon.name}</Card.Header>
        <Card.Description>
          <a href={pokemon.url} target="_blank" rel="noopener noreferrer">
            查看官方详情
          </a>
        </Card.Description>
      </Card.Content>
    </Card>
  );
};

export default PokeCard;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 10:52:32