undefined после setState () (использовать ловушку) в Reactjs - PullRequest
1 голос
/ 01 апреля 2020

я учусь реагировать и js сам. Пожалуйста, объясните, почему возникает такая ситуация. PS: простите за большой текст, я постарался объяснить проблему как можно яснее. Спасибо. Суть дела: через хук установить начальное состояние:

  const [pokemon, setPokemon] = useState({
    img: "",
    name: "",
    types: [],
    abilities: [],
    moveList: [],
    weight: "",
    height: "",
    description: "",
    genus: "",
    chanceToCatch: "",
    evolutionURL: ""
  });

далее я делаю api запросы на получение информации изнутри useEffect:

useEffect(() => {
    const fetchData = async () => {
      await Axios({
        method: "GET",
        url: urlPokemonAPI
      })
        .then(result => {
          const pokemonResponse = result.data;

          /* Pokemon Information */
          const img = pokemonResponse.sprites.front_default;
          const name = pokemonResponse.name;
          const weight = Math.round(pokemonResponse.weight / 10);
          const height = pokemonResponse.height / 10;
          const types = pokemonResponse.types.map(type => type.type.name);
          const abilities = pokemonResponse.abilities.map(
            ability => ability.ability.name
          );
          const moveList = pokemonResponse.moves.map(move => move.move.name);
          setPokemon(() => {
            return {
              img: img,
              name: name,
              weight: weight,
              types: types,
              abilities: abilities,
              moveList: moveList,
              height: height
            };
          });
        })

      await Axios({
        method: "GET",
        url: urlPokemonSpecies
      }).then(result => {
         let description = "";
         result.data.flavor_text_entries.forEach(flavor => {
          if (flavor.language.name === "en") {
           description = flavor.flavor_text;
          }
        });
        let genus = "";
        result.data.genera.forEach(genera => {
         if (genera.language.name === "en") {
          genus = genera.genus;
         }
        });
        const evolutionURL = result.data.evolution_chain.url;
        const eggGroups = result.data.egg_groups.map(
          egg_group => egg_group.name
        );
        const chanceToCatch = Math.round(
          (result.data.capture_rate * 100) / 255
        );
        setPokemon(pokemon => {
          return {
            ...pokemon,
            description: description,
            genus: genus,
            chanceToCatch: chanceToCatch,
            evolutionURL: evolutionURL,
            eggGroups: eggGroups
          };
        });
      });
    };
    fetchData();
  }, [urlPokemonAPI, urlPokemonSpecies]);

Проблема возникает именно с eggGroups (при одинаковой обработке abilities и types такой проблемы нет). И это то, что происходит, когда я хочу вывести данные на страницу в виде <div> Egg Group: {pokemon.eggGroups} </div>, данные отображаются нормально, но как только я хочу вывести eggGroups, а также abilities и types, разделенные запятыми (join ( ',')) - ошибка: TypeError: pokemon.eggGroups is undefined. Я решил проверить это через консоль и вставил ключ eggGroups в тайм-аут:

enter image description here

В какой-то момент eggGroups становится неопределенным ... почему, я не могу понять. Но если я устанавливаю состояние отдельно, как const [egg, setEgg] = useState ([]); setEgg (eggGroups);, то такой проблемы не наблюдается. почему это происходит? все было хорошо с types и abilities. Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 02 апреля 2020

В вашем коде есть проблема, это правильный способ ожидания с топором ios, вам нужно импортировать топор ios, как это

import axios from 'axios';

await должен вызываться с обещание, затем он возвращает данные из API следующим образом:

const result = await axios.get(urlPokemonAPI);

Это фрагмент кода с тем же логом c в ваш код

useEffect(() => {
    const fetchData = async () => {
        // import axios from 'axios';
        try {
            const result = await axios.get(urlPokemonAPI);
            const pokemon = result.data;
            setPokemon({
                img: pokemon.sprites.front_default,
                name: pokemon.name,
                weight: Math.round(pokemon.weight / 10),
                types: pokemon.types.map(i => i.type.name),
                abilities: pokemon.abilities.map(i => i.ability.name),
                moveList: pokemon.moves.map(i => i.move.name),
                height: pokemon.height / 10
            });

            const result2 = await axios.get(urlPokemonSpecies);
            const data = result2.data;
            let description = "";
            data.flavor_text_entries.forEach(i => {
                const lang = i.language.name
                if (lang === "en") {
                    description = i.flavor_text;
                }
            });
            let genus = "";
            data.genera.forEach(i => {
                const lang = i.language.name;
                if (lang === "en") {
                    genus = i.genus;
                }
            });
            setPokemon(pokemon => {
                return {
                    ...pokemon,
                    description,
                    genus,
                    chanceToCatch: Math.round((data.capture_rate * 100) / 255),
                    evolutionURL,
                    eggGroups: data.egg_groups.map(g => g.name)
                };
            });
        } catch (e) {
            console.log(e);
        }
    };
    fetchData();
}, [urlPokemonAPI, urlPokemonSpecies]);

Вы видите другой проблема: вы вызываете setPokemon два раза , давайте перепишем его снова:

useEffect(() => {
    const fetchData = async () => {
        // import axios from 'axios';
        try {
            const result = await axios.get(urlPokemonAPI);
            const data1 = result.data;
            const result2 = await axios.get(urlPokemonSpecies);
            const data2 = result2.data;
            function resolveDescription(data) {
                let description = "";
                data.flavor_text_entries.forEach(i => {
                    const lang = i.language.name
                    if (lang === "en") {
                        description = i.flavor_text;
                    }
                });
                return description;
            }
            function resolveGenus(data) {
                let genus = "";
                data.genera.forEach(i => {
                    const lang = i.language.name;
                    if (lang === "en") {
                        genus = i.genus;
                    }
                });
                return genus;
            }

            setPokemon({
                img: data1.sprites.front_default,
                name: data1.name,
                weight: Math.round(data1.weight / 10),
                types: data1.types.map(i => i.type.name),
                abilities: data1.abilities.map(i => i.ability.name),
                moveList: data1.moves.map(i => i.move.name),
                height: data1.height / 10,
                description: resolveDescription(data2),
                genus: resolveGenus(data2),
                chanceToCatch: Math.round((data2.capture_rate * 100) / 255),
                evolutionURL: data2.evolution_chain.url,
                eggGroups: data2.egg_groups.map(g => g.name)
            });
        } catch (e) {
            console.log(e);
        }
    };
    fetchData();
}, [urlPokemonAPI, urlPokemonSpecies]);
1 голос
/ 01 апреля 2020

средство обновления состояния из ловушек не объединяет значения состояния при обновлении состояния, вместо этого оно просто заменяет старое значение новым

, поскольку используется средство обновления состояния, например

 setPokemon(() => {
        return {
          img: img,
          name: name,
          weight: weight,
          types: types,
          abilities: abilities,
          moveList: moveList,
          height: height
        };
      });

eggGroups свойство потеряно и, следовательно, оно становится неопределенным. Вам необходимо обновить его, распространяя предыдущие значения состояния, полученные из обратного вызова

setPokemon((prev) => {
        return {
          ...prev
          img: img,
          name: name,
          weight: weight,
          types: types,
          abilities: abilities,
          moveList: moveList,
          height: height
        };
      });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...