简体   繁体   English

更改组件状态 - REACT

[英]Change component state - REACT

I'm currently working on a project with the Pokemon API and i'm facing a problem.我目前正在使用 Pokemon API 开展一个项目,但我遇到了一个问题。 I want to change the value parameter in the async function getPokemonTypes(), but the value I receive in handleSelect() is not working.我想更改异步函数 getPokemonTypes() 中的 value 参数,但我在 handleSelect() 中收到的值不起作用。 On the console.log(value), the value changes every time I select a different option.在 console.log(value) 上,每次我选择不同的选项时,值都会发生变化。 Could someone tell me what I'm doing wrong?有人可以告诉我我做错了什么吗?

import React from 'react'
import { useState, useEffect } from "react";
import { Link } from 'react-router-dom'

async function getPokemonTypes(value) {

    const response = await fetch(`https://pokeapi.co/api/v2/type/${value}`)
    const data = await response.json()
    console.log(data)
    return data
}

async function getPokemonInfo(pokemonId) {

    const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${pokemonId}`)
    const data = await response.json()
    return data
}


export const PokemonTypesCard = () => {

    const [pokemonTypesCard, setPokemonTypesCard] = useState({})
    const [pokemonIdNumber, setPokemonIdNumber] = useState([])
    const [value, setValue] = useState('normal')

    const handleSelect = (value) => {
        setValue(value)
      }
      console.log(value)
    useEffect(() => {

        async function fetchData() {

            const pokemonTypesCard = await getPokemonTypes(value)
            const pokemonIdText = pokemonTypesCard.pokemon.map((item) => {
                return item.pokemon.name
            })
            const data = pokemonIdText.map(async (pokemonId) => {
                return (
                    await getPokemonInfo(pokemonId)
                )
            })
            const pokemonIdNumber = await Promise.all(data)
            setPokemonIdNumber(pokemonIdNumber)
            setPokemonTypesCard(pokemonTypesCard)
        }
        fetchData()
    }, [])

    return (
        <section>

            <div>
                <label htmlFor='pokemon-types'>Choose a pokemon type</label>
                <form>
                    <select onChange={(event) => handleSelect(event.target.value)}
        value={value}>
                        <option value='normal'>Normal</option>
                        <option value='fighting'>Fighting</option>
                        <option value='flying'>Flying</option>
                        <option value='poison'>Poison</option>
                        <option value='ground'>Ground</option>
                        <option value='rock'>Rock</option>
                        <option value='bug'>Bug</option>
                        <option value='ghost'>Ghost</option>
                        <option value='steel'>Steel</option>
                        <option value='fire'>Fire</option>
                        <option value='water'>Water</option>
                        <option value='grass'>Grass</option>
                        <option value='electric'>Electric</option>
                        <option value='psychic'>Psychic</option>
                        <option value='ice'>Ice</option>
                        <option value='dragon'>Dragon</option>
                        <option value='dark'>Dark</option>
                        <option value='fairy'>Fairy</option>
                        <option value='shadow'>Shadow</option>
                    </select>
                </form>

            </div>

            {<div>
                <ul>
                    {!pokemonIdNumber ? '' : pokemonIdNumber.map((item, index) =>
                        <li key={index}>
                            <Link to={`/pokemon/${item.id}`}>
                                <img
                                    src={`https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/${item.id}.png`}
                                    alt={item.name}
                                />
                            </Link>
                            <p>{item.name}</p>
                        </li>
                    )}
                </ul>
            </div>}

        </section>
    );
}

You need to add type to the dependnecies array of useEffect :您需要将type添加到useEffect的依赖项数组中:

useEffect(() => {
    async function fetchData() {
        const pokemonTypesCard = await getPokemonTypes(value);
        const pokemonIdText = pokemonTypesCard.pokemon.map((item); => {
            return item.pokemon.name;
        });
        const data = pokemonIdText.map(async (pokemonId) => {
            return (
                await getPokemonInfo(pokemonId)
            );
        });
        const pokemonIdNumber = await Promise.all(data);
        setPokemonIdNumber(pokemonIdNumber);
        setPokemonTypesCard(pokemonTypesCard);
    }

    fetchData();
}, [value]); // <= HERE

Keep in mind this code has some issues, as you might end up seeing data for a type that doesn't match the one in the URL if something like this happens:请记住,此代码存在一些问题,因为如果发生这种情况,您最终可能会看到与 URL 中的类型不匹配的类型的数据:

  • You select fire and getPokemonTypes('fire') is called.您选择firegetPokemonTypes('fire')
  • You select to ice and getPokemonTypes('ice') is called.您选择icegetPokemonTypes('ice')
  • getPokemonTypes('ice') finishes loading and the rest of the fetchData function executes. getPokemonTypes('ice')完成加载并执行fetchData函数的其余部分。
  • getPokemonTypes('fire') finishes loading and the rest of the fetchData function executes. getPokemonTypes('fire')完成加载并执行fetchData函数的其余部分。
  • The selected option is now ice but see data from fire .选择的选项现在是ice但查看来自fire的数据。

The proper way to do it would be like this:正确的方法是这样的:

useEffect(() => {
    let shouldUpdate = true;

    async function fetchData() {
        const pokemonTypesCard = await getPokemonTypes(value);

        if (!shouldUpdate) return;

        const pokemonIdText = pokemonTypesCard.pokemon.map((item) => {
            return item.pokemon.name;
        });

        const data = pokemonIdText.map((pokemonId) => {
            return getPokemonInfo(pokemonId);
        });

        const pokemonIdNumber = await Promise.all(data);

        if (!shouldUpdate) return;

        setPokemonIdNumber(pokemonIdNumber);
        setPokemonTypesCard(pokemonTypesCard);
    }

    fetchData();

    // This cleanup function will be called if the `useEffect`'s
    // dependencies change, so if you run it twice in a row for
    // different types, when the result of the first one arrives,
    // it will be discarded:
    return () => {
        shouldUpdate = false;
    };
}, [value]);

Also, you have an error here:此外,您在这里有一个错误:

const data = pokemonIdText.map(async (pokemonId) => {
    return (
        await getPokemonInfo(pokemonId)
    );
});

const pokemonIdNumber = await Promise.all(data);

You want to store all those promises in the data array and await them all together with Promise.all below, but you are instead awaiting them one by one.您想将所有这些 Promise 存储在data数组中,并与下面的Promise.all一起等待它们,但您却是一个接一个地等待它们。 It should be like this:它应该是这样的:

const data = pokemonIdText.map((pokemonId) => {
    return getPokemonInfo(pokemonId);
});

const pokemonIdNumber = await Promise.all(data);

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

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