当前位置: 首页 > 知识库问答 >
问题:

当将对象数组映射到React元素时,其中一个属性会消失

高玮
2023-03-14

我正在尝试制作一个反应应用程序来从口袋妖怪api(https://pokeapi.co/docs/v2#pokemon)中获取数据并将其显示在网格中。

我的组件树:

应用程序-

在应用程序组件中,我获取口袋妖怪数据,我得到20个第一个结果,并将结果数组映射到每个口袋妖怪的网址也被获取的数组中(数组中的每个对象都有一个“名称”、“网址”和“信息”属性)。信息属性保存每个单独获取的所有数据。

在使用这个数组作为道具呈现Pokedex之后,在Pokedex组件中,我将数组映射到一个元素数组,其中只包含我想要显示的数据(名称,以及“info”属性中的一些属性)。

下面是引发错误的代码:

export class Pokedex extends React.Component {
  render() {
    console.log("this.props.pokeArray:", this.props.pokeArray); // shows pokemons with the 3 properties
    const elements = this.props.pokeArray.map((pokemon, i) => {
      console.log(pokemon); // logs the pokemon without the info property
      return (
        <PokeCard
          key={`poke${i}`}
          id={pokemon.info.id} //error raised here: Cannot read property 'id' of undefined
          name={pokemon.name}
          types={pokemon.info.types}
          sprite={pokemon.info.sprites["front_default"]}
        />
      );
    });

    return (
      <div className="pkdx-pokedex-container">
        <h1>Pokedex</h1>
        {elements}
      </div>
    );
  }
}

下面是它的父元素App的代码

import "./App.css";
import { Pokedex } from "./components/Pokedex/Pokedex";
import { useQuery } from "react-query";
import { ReactQueryDevtools } from "react-query-devtools";

// *** Base API url

const url = "https://pokeapi.co/api/v2/pokemon";

// *** Async, because we need to have the data before second fetch

async function fetchPokemon() {
  const response = await fetch(url);

  const data = (await response.json()).results;

  // *** Keep url of fetch and add new info property to each pokemon

  data.forEach(async (poke) => {
    const res = await fetch(poke.url);
    poke.info = await res.json();
  });

  return data;
}

function App() {
  const info = useQuery("fetchPokemon", fetchPokemon);

  if (info.status === "success") {
    console.log("pokeArray:", info.data); // each Pokemon has the three properties
    return (
      <div>
        <Pokedex pokeArray={info.data} />;
        <ReactQueryDevtools />
      </div>
    );
  } else return null;
}

export default App;

我不知道我是否遗漏了什么,但我不明白为什么它没有显示“info”属性。

共有2个答案

卢聪
2023-03-14

看起来你正在做一个异步的forEach而不是等待它。您可能希望更改为映射,并执行const data=wait Promise。全部(data.map(…) 以确保数据已加载。

我举了一个例子。看看:

import React from "react";
import { useQuery } from "react-query";
import { ReactQueryDevtools } from "react-query-devtools";

export class Pokedex extends React.Component {
  render() {
    console.log("this.props.pokeArray:", this.props.pokeArray); // shows pokemons with the 3 properties
    const elements = this.props.pokeArray.map((pokemon, i) => {
      console.log("POKEMON", pokemon); // logs the pokemon without the info property
      return (
        <React.Fragment key={i}>
          <div>key={`poke${i}`}</div>
          <div>id={pokemon.info.id}</div>
          <div>name={pokemon.name}</div>
          <div>sprite={pokemon.info.sprites["front_default"]}</div>
        </React.Fragment>
      );
    });

    return (
      <div className="pkdx-pokedex-container">
        <h1>Pokedex</h1>
        {elements}
      </div>
    );
  }
}

// *** Base API url

const url = "https://pokeapi.co/api/v2/pokemon";

// *** Async, because we need to have the data before second fetch

async function fetchPokemon() {
  const response = await fetch(url);

  const data = (await response.json()).results;

  // *** Keep url of fetch and add new info property to each pokemon

  const x = await Promise.all(
    data.map(async (poke) => {
      const res = await fetch(poke.url);
      return {
        ...poke,
        info: await res.json()
      };
    })
  );

  return x;
}

function App() {
  const info = useQuery("fetchPokemon", fetchPokemon);

  if (info.status === "success") {
    console.log("pokeArray:", info.data); // each Pokemon has the three properties
    return (
      <div>
        <Pokedex pokeArray={info.data} />;
        <ReactQueryDevtools />
      </div>
    );
  } else return null;
}

export default App;

麻鸿熙
2023-03-14

这里的问题在于fetchPokemon。在forEach回调中使用await fetch(poke.url)时,回调将愉快地等待响应。但是,forEach不处理回调返回的promise。意思是口袋妖怪。info属性是在数据从fetchPokemon函数返回一段时间后设置的。

要解决这个问题,请使用map()来存储生成的promise,然后使用Promise.all()来等待要解决的promise列表。

async function fetchPokemon() {
  const response = await fetch(url);
  const data = (await response.json()).results;

  await Promise.all(data.map(async (pokemon) => {
    const res = await fetch(pokemon.url);
    pokemon.info = await res.json();
  }));

  return data;
}

异步函数总是返回promise,因此将异步函数传递给map()将把当前数组元素映射到promise。然后可以将该数组传递给Promise。all()将等待所有promise完成。由于map()回调中没有返回值,所以promise将全部解析为undefined,但是数据存储在data中,因此我们可以返回该值。

const url = "https://pokeapi.co/api/v2/pokemon";

async function fetchPokemon() {
  const response = await fetch(url);
  const data = (await response.json()).results;

  await Promise.all(data.map(async (pokemon) => {
    const res = await fetch(pokemon.url);
    pokemon.info = await res.json();
  }));

  return data;
}


fetchPokemon().then(pokemon => {
  document.body.textContent = JSON.stringify(pokemon);
});

 类似资料:
  • 我正在尝试将我的对象[]数组映射并过滤到int[]数组。如果对象是int,效果很好,但如果不是int,则抛出强制转换异常。我想知道我是否可以在lambda表达式中附加一个try/catch?这是我的代码: 或者更好的方法是试着抓住整个街区?

  • 问题内容: 我的ViewValue类定义如下: 在我的代码中,我需要将ViewValue实例列表转换为包含来自相应ViewValue的id字段值的列表。 我用foreach循环来做: } 有没有更好的方法来解决这个问题? 问题答案: 编辑:此答案基于以下想法:您需要对代码中其他位置的不同实体和不同属性执行类似的操作。如果您 只需 要按ID将ViewValues列表转换为Longs列表,则请坚持使用

  • 问题内容: 我有一个用于向用户提供数据的组件。例如。该组件可以调度某些方法(例如,按操作)。我目前正在使用一种方法来映射到。派遣后有办法吗? 问题答案: 据我了解,您要做的就是将组件的props转换为组件自己的状态。您总是可以像这样在组件的生命周期方法中将组件的props更改为组件的状态。 每当有新的道具进入组件时,方法总是由react执行,因此这是根据道具更新组件状态的正确位置。 更新: The

  • 当遍历ACROD时,有一个列表,并希望将该列表中的第一个对象映射到我的域对象。 @mapping(source=“insurancesvcrqs[0].policyquoteinqrqsaddrqsandpolicyquoteinqrqs[0].productues[0].generalpartyinfo.nameinfos[0].commlname.commericalname”,target=

  • 使用一个函数将数组的值映射到对象,其键值对中,原始值作为键,映射值作为值。 使用一个匿名的内部函数作用域来声明一个 undefined 的内存空间,使用闭包来存储返回值。 使用一个新的 Array 来存储带有函数映射的数组和一个逗号运算符来返回第二个步骤,而不需要从一个上下文移动到另一个上下文(由于闭包和操作顺序)。 const mapObject = (arr, fn) => (a => (

  • 基本上,我收到的数据是这样的。 我试着在React 16.9中以表格的形式显示它,如下所示。 我的问题是参与者通常是一个对象数组,并且不显示,我的问题是我如何能够显示或映射对象数组到表的一行。