Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/395.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React和PokéAPI:通过映射多个对象数组来获取Pokémon信息只会给我提供一个Pokémon的信息_Javascript_Reactjs_Rest_Api - Fatal编程技术网

Javascript React和PokéAPI:通过映射多个对象数组来获取Pokémon信息只会给我提供一个Pokémon的信息

Javascript React和PokéAPI:通过映射多个对象数组来获取Pokémon信息只会给我提供一个Pokémon的信息,javascript,reactjs,rest,api,Javascript,Reactjs,Rest,Api,我正在做一个个人项目来练习React,这是一个Pokédex应用程序 我在这里同时使用React和PokéAPI。我将在这个问题的底部显示代码片段 我不得不做两个API调用,因为第一个是关于获取神奇宝贝的名称,第二个是检索需要神奇宝贝名称的更多信息 挑战是,我要找回关于每个神奇宝贝的信息对象,我需要数组,这样我就可以在JSX渲染中映射我需要的内容。因此,我使用了Object.values方法,这不可避免地导致我拥有一个可以迭代的对象数组,这太棒了 然而,现在当我映射所有我想要的对象时,我只得到最

我正在做一个个人项目来练习React,这是一个Pokédex应用程序

我在这里同时使用React和PokéAPI。我将在这个问题的底部显示代码片段

我不得不做两个API调用,因为第一个是关于获取神奇宝贝的名称,第二个是检索需要神奇宝贝名称的更多信息

挑战是,我要找回关于每个神奇宝贝的信息对象,我需要数组,这样我就可以在JSX渲染中映射我需要的内容。因此,我使用了Object.values方法,这不可避免地导致我拥有一个可以迭代的对象数组,这太棒了

然而,现在当我映射所有我想要的对象时,我只得到最新的神奇宝贝渲染,也就是说,假设我想查看有关151神奇宝贝的信息,我将只能在屏幕上看到Mew和151[这是我询问的名称和ID]

在下面的代码片段中,我只是将限制改为9神奇宝贝,这样我就不需要加载太多数据来查看代码是否正常工作:

import React, { Component } from 'react';
import './App.css';
import PokemonCard from './PokemonCard';
import axios from 'axios';

class App extends Component {
  constructor() {
    super();
    this.state = {
      pokemonInfo:[],
      result: [],
      pokemonName: "",
      pokemonID: [],
      introRegion: "",
      primaryType: "",
      secondaryType: "",
    }
  }

  componentDidMount() {

      axios({
        method:'GET',
        url: `https://pokeapi.co/api/v2/pokemon/?limit=9`,
        dataResponse: 'json',
      })
        .then((dataOne) => {
          console.log(dataOne.data.results)

          this.setState({
            result: dataOne.data.results
          })

          this.state.result.map(async(fetchInfo) => {
            return axios({
                method: 'GET',
                url: `${fetchInfo.url}`,
                dataResponse: 'json',
              })
              .then( (dataTwo) =>{
                const dataTwoArray = Object.values(dataTwo)
                console.log(dataTwoArray)

                this.setState({
                  pokemonInfo: [dataTwoArray]
                })
              });
          })
        });
  }

    render() {
        return (
            <div className="App">

            <h1>Pokédex!</h1>

            {this.state.pokemonInfo.map((getInfo) => {
              return (
                <>
                  <h3>{getInfo[0].id}</h3>

                  <h3>{getInfo[0].name}</h3>

                </>
              )
            })}
            {/* <PokemonCard /> */}


            </div>
        );
    }
}

export default App;
我想看看我一直想要的所有神奇宝贝的名字和身份证。
任何帮助都将不胜感激

因此,您在这里的尝试有几个问题。其中一些与你的问题有关,另一些则不太相关

深入到与您的问题相关的问题:您似乎对setState的工作有误解。函数setState获取新状态的部分版本,并创建下一个状态,然后在状态更新后重新呈现组件。关键是它是对状态的局部视图,而不是对现有状态的修改。我将在第2点中详细说明这一点

1首先,调用setState将结果更新为API响应,然后立即使用this.state.result进行后续操作-这可能会起作用,但问题很大。您不应该依赖于setState何时更新了this.state。通常情况下,您已经拥有了您以任何方式传递的数据,因此只需使用这些数据即可。在这种情况下,不应映射this.state.result,而应映射dataOne.data.results。在setState之后使用this.state是可能的,但这是一个等待发生的竞争条件噩梦,是非常糟糕的做法。现在就打破它

2第二,也是我前面提到的一点。setState正在对下一个状态进行局部查看。因此,当您调用这个.setState{pokemonInfo:[datatwarray]}时,您不是说将这个新值添加到pokemonInfo中的数组中,而是说用这个新的信息列表替换当前的信息列表。我不太喜欢推荐这个,因为它回到了第一部分的问题,但是您可以通过扩展现有阵列和/或浓缩新阵列来解决这个问题。this.setState{pokemonInfo:this.state.pokemon.concat[dataTwoArray]}或更现代的this.setState{pokemonInfo:[…this.state.pokemonInfo,dataTwoArray]}。这两种方法都取决于之前对setState的调用是否成功,以便相应地捕获所有现有值,这是有问题的

好的,问题是当你更新pokemonInfo时,你只将它设置为数组中的一个值。在这样做的过程中,您通常只能看到更准确地完成请求的最后一个

现在,我说我对问题2的解决方案不好,而且是这样。因为你真的在建立一个承诺列表,并且你想等待它们全部完成,所以你应该做更多的承诺

// inside the first promise's then

// We start by starting a request promise by mapping each pokemon
// data to a request. This results in pokePromises being an array
// of Promise objects.
const pokePromises = dataOne.data.results.map(pokemon => axios({
  method: 'GET',
  url: pokemon.url, // notice no need here to make it a string, it's already a string!
  dataResponse: 'json',
}));

// Now wait for all the requests to finish before doing more, Promise.all
// creates a promise that will resolve when all given promises have been
// resolved. This doesn't handle errors though, we're assuming all success
// here.
Promise.all(pokePromises).then(allPokeData => {
  // This takes each response object and converts into a an array 
  // of values, just like you do already. We're just operating on
  // all the results at one time instead of one result like you are.
  const pokemonInfo = allPokeData.map(data => Object.values(data));

  // Now that we have all the data we set the state, but we use
  // an ES6 shorthand that expands to `{ pokemonInfo: pokemonInfo }`
  this.setState({ pokemonInfo });
});
代码沙盒:

另一个可能减少更改量的选项是将更新函数传递给setState,而不是对象

这需要您对pokemonInfo的最终更新如下:

// This way of updating state guarantees we get the current version 
// of state (in the updater function) when this update is being
// applied and can ensure us that our new pokemonInfo will truly contain
// the previous and new values as expected.
this.setState(state => ({
  ...state, // merge in previous state
  pokemonInfo: [...state.pokemonInfo, dataTwoArray],
}));
代码沙盒:

代码中的其他问题是名称。与dataOne一样,dataTwo和dataTwoArray在读取代码的上下文中没有任何意义。他们现在可能对你有一些意义,但当你回来看这个项目的时候,他们不会在一个月或更长的时间内。对于阅读您的代码的任何其他人来说,它们也没有任何意义。您应该努力使用有意义且可读的名称。所以dataOne应该是Pokelistrensponse,也许dataTwo应该是pokeData或pokemonResponse,fetchInfo是一个神奇宝贝,所以称它为pokemon,对吗?还要注意您的数据类型。fetchInfo.url是一个字符串,插入字符串是无意义和冗余的。也要注意缩进和间距。它可以是StackOverflow的格式,也可以是您使用的任何编辑器,但它到处都是。间隔是一件好事,它为代码增加了秩序和清洁度。对可读性来说非常必要

不管是谁,希望你能找到一些和/或所有这些有用的东西。了解React组件生命周期的工作方式以及upda的工作方式
ting state与重新渲染以及对JS的更深入理解密切相关。至少从这个代码示例来看,您似乎有一些表面知识。不断成长,扩大你的知识财富

this.setState是一个异步操作。您不应该依赖于this.setState之后立即填充this.state。相反,也许可以循环使用dataOne.data,但可能还有其他问题布兰登,你的评论确实帮助了我的工作,为此我感谢你。我意识到我需要更多地了解react中的状态和生命周期,因为它们可能会变得有点混乱和混乱。这需要一些练习,这正是为什么我要用React来构建它,熟能生巧。感谢您告诉我一些最佳实践,例如在更新状态时不使用状态,等等。。。不过,我有一个问题。为什么我们使用Promise.all而不是.then.catch方法?我还在努力学习,所以你说的任何话都会有帮助!干杯:@sizreem我使用了Promise.all,因为axios返回一个承诺,该承诺在请求完成时解析/拒绝。由于更新状态中的数组需要它的当前值,所以我认为最好等到每个pokémon的所有请求都完成后再进行更新-因此我创建了请求并使用Promise.all,当所有pokémon请求都完成时,它会进行解析。或者,第二种方法使用setState的另一种实现,它采用一个更新函数,该函数保证获取最新状态,因此不需要Promise.all-希望这会有所帮助。