在 React 中使用 API 时无法读取未定义错误的属性

Cannot read properties of undefined error when working with an API in React

我正在从 API 中获取数据,其中 returns 对象数组采用这种格式。

{Name: 'hitmonchan', Description: 'Fighting-type Pokémon introduced in Generation I'}
{Name: 'Gogoat', Description: 'A quadrupedal, hooved Pokémon similar to a goat'}... and so on

这是我正在尝试做的事情。我取出所有超过 500 只的小精灵,将它们塞入一个名为 allPokemons 的数组中。然后我想用列表中的 4 个随机口袋妖怪做一些事情。所以我将有一个名为 smallRandomPokemonArray 的数组,其中只有从 allPokemon 数组中随机选择的四个口袋妖怪。

import { useEffect, useState } from 'react';
import { getallPokemons } from '../services/pokemonapi';

const empty_pokemon = {
    'Name': '',
    'Description': ''
}

function PokemonComponent() {


    const [allPokemons, setAllPokemons] = useState([]);
    const [smallRandomPokemonArray, setSmallRandomPokemonArray] = useState([]);

    useEffect(() => {
        getAll();
    }, []);

    const getAll = () => {
        getallPokemons()
            .then(data => {

                //actual data with over 500 objects show in log
                console.log(data);
                setAllPokemons(data);
                randomChooser(data.length)
            })
    }

    const randomChooser = (length) => {
        let temporaryArray = [];
        for (let i = 0; i < 4; i++) {
            const randomIndex = Math.floor(Math.random() * length);

            //First Problem: this is returning index in numbers followed by undefined... why?
            console.log(randomIndex + " " + allPokemons[randomIndex]);
            temporaryArray.push(allPokemons[randomIndex]);

            //Second Problem: this is also returning "temp undefined"
            console.log("temp " + temporaryArray[i]);
        }
        setSmallRandomPokemonArray(temporaryArray);
    }

    return (
        <>
            <div className="pokemondiv">
                {
                    smallRandomPokemonArray.map((element) => (
                        <div>
                            <p>{element.Name}</p>
                            <p>{element.Description}</p>
                        </div>
                    ))
                }
            </div>
        </>
    )
}

export default PokemonComponent;

当我尝试从 setSmallRandomPokemonArray 中打印值时,我得到了错误:

Uncaught TypeError: Cannot read properties of undefined (reading 'Name')

此外,请查看代码中的 First problem and Second problem 部分。它们在 console.log 中也显示为未定义。根据我的理解,它应该可以工作,因为当我开始随机化它时 allPokemons 已经存在。然后我将四个随机值推送到 smallRandomPokemonArray。我不知道为什么会抛出错误。

问题

您正在 getAllsetAllPokemons(data); 之后呼叫 randomChooser(data.length)。此时randomChooser里面使用的allPokemons还是[].

emptyArray[0] = undefined. undefined.Name = Cannot read properties of undefined. The takeaway is that when you call a setState, the related state is updated asynchronously. A re-render is needed to have the updated value.

第 1 个解决方案

getAll 更改为下面的代码,因此它唯一的工作就是填充 allPokemons 状态:

const getAll = () => {
  getallPokemons().then((data) => {
    setAllPokemons(data);
  });
};

使用 useEffect 获取您需要的四个口袋妖怪:

useEffect(() => {  
  /*
    I moved randomChooser here, so you don't have to put it in useEffect's 
    dependencies array, which if you do, you should wrap randomChooser in a 
    useCalback, as otherwise you get an infinite call.
  */
  const randomChooser = (length) => {
    const temporaryArray = [];
    for (let i = 0; i < 4; i++) {
      const randomIndex = Math.floor(Math.random() * length);
      temporaryArray.push(allPokemons[randomIndex]);
    }
    setSmallRandomPokemonArray(temporaryArray);
  };
  if (allPokemons.length <= 0) return;
  randomChooser(allPokemons.length);
}, [allPokemons]);

解决方案 2

更改 randomChooser 以便它接收数组,而不是它的长度:

const randomChooser = (allPokemons) => {
  let temporaryArray = [];
  for (let i = 0; i < 4; i++) {
    const randomIndex = Math.floor(Math.random() * allPokemons.length);
    temporaryArray.push(allPokemons[randomIndex]);
  }
  setSmallRandomPokemonArray(temporaryArray);
};

更改 getAll 以便您将数据提供给 randomChooser:

const getAll = () => {
  getallPokemons().then((data) => {
    setAllPokemons(data);
    randomChooser(data);
  });
};

您在randomChooser中使用它的地方尚未设置allPokemons。 react 将在函数完成后设置所有状态 运行。 您需要将数据传递到 randomChooser.

 const randomChooser = (data) => {
    const length = data.length
    let temporaryArray = [];
    for (let i = 0; i < 4; i++) {
        const randomIndex = Math.floor(Math.random() * length);

        //First Problem: this is returning index in numbers followed by undefined... why?
        console.log(randomIndex + " " + data[randomIndex]);
        temporaryArray.push(data[randomIndex]);

        //Second Problem: this is also returning "temp undefined"
        console.log("temp " + temporaryArray[i]);
    }
    setSmallRandomPokemonArray(temporaryArray);
}