如何让 setState 在 useEffect 中生效

How to make setState working in useEffect

我正在使用 fetch API 从 API 中获取。
获取结果后,我想将 setState 设置为无效的结果
这是获取结果的函数

export const random = (min, max) => Math.floor(Math.random() * (max - min)) + min;


export const getPokemons = async function () {
  const pokemon = [];
  for (let i = 0; i < 5; i++) {
    pokemon.push(fetch(`https://pokeapi.co/api/v2/pokemon/${random(1, 800)}`));
  }
  return Promise.all(pokemon)
    .then((data) => {
      const parsedData = [];
      data.forEach(async (d) => {
        const resJson = await d.json()
        parsedData.push(resJson);
      });
       return parsedData
    })
    .catch((err) => {
      console.log(err);
    });
};

导入代码

  const [stats,setStats] = useState([])
  useEffect(()=>{
      generateTrio()  
        },[])
        
    async function generateTrio() {
        const gTrio = await getPokemons();
        setStats(gTrio)
        console.log(stats,gTrio)
        }

这里的 stats 是一个空数组,而 gTrio 是必需的结果我想在 setStats

usestate 的set 函数不会立即和同步地设置状态。我认为它像异步方法。但这不仅是真正的原因。 您可以在类似主题中查看此消息。

问题是双重的:

  • 您在调用 setStats() 的同一个闭包中记录 stats。请参阅 以了解为什么这样做会记录之前的状态。
  • 您正在将 async 函数传递给 forEach() 的回调函数,该函数在外部 promise 使用最初为空的数组解析后将数据推送到数组中。有关此反模式的潜在陷阱,请参阅

您的 getPokemons() 从您的异步函数返回一个空数组,然后异步填充它 它用于呈现您的 Main 组件。

即使您在正确的闭包中记录 stats,Chrome 的开发人员控制台输出也会令人困惑,因为它会向您显示数组已填充,即使它在它被记录的时间。有关此开发者控制台行为的更多信息,请参阅 Is Chrome's JavaScript console lazy about evaluating arrays?

getPokemons() 的一种正确写法是:

export const getPokemons = () => (
  Promise.all(
    Array.from({ length: 5 }, async () => {
      const response = await fetch(`https://pokeapi.co/api/v2/pokemon/${random(1, 800)}`);
      return response.json();
    })
  )
);

编写 Main 组件的正确方法是:

const Wrapper = styled.div``;

const Main = () => {
  const [stats, setStats] = useState([]);

  useEffect(() => {
    const setPokemons = async () => {
      setStats(await getPokemons());
    };

    setPokemons();  
  }, []);

  // console.log(stats);

  const names = stats.map(item => ( 
    <p key={item.id}>{item.name}</p> 
  ));

  return (
    <Wrapper>
      {names}
    </Wrapper>
  );
}

export default Main;