简体   繁体   English

在 Reactjs 中 setState() 之后未定义(使用钩子)

[英]undefined after setState() (use hook) in Reactjs

I learn react and js myself.我自己学习 react 和 js。 please explain why this situation occurs.请解释为什么会出现这种情况。 PS: excuse me for the large text, I tried to explain the problem as clearly as possible. PS:请原谅我的大文字,我试图尽可能清楚地解释问题。 thanks.谢谢。 Essence of the matter: set the initial state through the hook:实质:通过钩子设置初始状态:

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

further I make api requests to get information from inside useEffect:此外,我发出 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]);

The problem arises specifically with eggGroups (with identical handling of abilities and types there is no such problem).这个问题特别出现在eggGroups (相同处理abilitiestypes ,没有这样的问题)。 And this is what happens when I want to output data to a page as <div> Egg Group: {pokemon.eggGroups} </div> the data is displayed normally, but as soon as I want to output eggGroups as well as abilities and types separated by commas ( join ( ',') ) - error: TypeError: pokemon.eggGroups is undefined .这就是当我想将数据作为<div> Egg Group: {pokemon.eggGroups} </div>输出到页面时会发生的情况,数据显示正常,但是一旦我想输出eggGroups以及abilities和用逗号分隔的typesjoin ( ',') ) - 错误: TypeError: pokemon.eggGroups is undefined I decided to check this matter through the console and stuffed this eggGroups key into the timeout:我决定通过控制台检查这件事并将这个eggGroups键塞进超时:

在此处输入图片说明

At some point, eggGroups becomes undefined ... why, I can't understand.在某些时候, eggGroups变得未定义......为什么,我无法理解。 But if I set the state separately, like const [egg, setEgg] = useState ([]); setEgg (eggGroups);但是如果我单独设置状态,比如const [egg, setEgg] = useState ([]); setEgg (eggGroups); const [egg, setEgg] = useState ([]); setEgg (eggGroups); such a problem is not observed.没有观察到这样的问题。 why is this happening?为什么会这样? everything was fine with types and abilities .一切都很好, typesabilities Thank you in advance.先感谢您。

state updater from hooks doesn't merge the state values when updating state, instead it just replaces the old value with new one来自钩子的状态更新器在更新状态时不合并状态值,而是用新值替换旧值

Since you use state updater like由于您使用状态更新程序,例如

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

eggGroups property is lost and hence it becomes undefined. eggGroups属性丢失,因此它变得未定义。 You need to update it by spreading the previous state values obtained from callback您需要通过传播从回调获得的先前状态值来更新它

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

Your code have a problem, this is the proper way to do await with axios, you need to import axios like this您的代码有问题,这是使用 axios 进行等待的正确方法,您需要像这样导入 axios

import axios from 'axios';

the await should be call with a promise, then it return the data from api like this: await应该使用承诺调用,然后它从 api 返回数据,如下所示:

const result = await axios.get(urlPokemonAPI);

This is the code snippet with the same logic to your code这是与您的代码具有相同逻辑的代码片段

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]);

do you see another problem: you call setPokemon two times , let's rewrite it again:你看到另一个问题:你调用 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]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM