【问题标题】:How to avoid unnecessary API calls with useEffect?如何使用 useEffect 避免不必要的 API 调用?
【发布时间】:2022-08-09 18:38:15
【问题描述】:

我仍然是 ReactJS 的初学者,并且在渲染列表时遇到了麻烦。

我不知道为什么,一直在对我的 API 进行调用。由于我没有对 useEffect 施加任何依赖,也就是说,我应该只渲染我的函数一次。

我不明白为什么会这样。你能告诉我我做错了什么吗?

这是我输入codesandbox.io的代码

import React from \"react\";
import axios from \"axios\";
import \"./styles.css\";

const App = () => {
  const BASE_URL = \"https://pokeapi.co/api/v2\";

  const [pokemons, setPokemons] = React.useState([]);

  const getAllPokemons = async () => {
    const { data } = await axios.get(`${BASE_URL}/pokemon`);

    data.results.map((pokemon) => getPokeType(pokemon));
  };

  const getPokeType = async (pokemon) => {
    const { data } = await axios.get(pokemon.url);

    setPokemons((prev) => [...prev, data]);
  };

  React.useEffect(() => {
    getAllPokemons();
  }, []);

  console.log(pokemons);

  return (
    <div className=\"App\">
      <h1>Hello CodeSandbox</h1>
      {pokemons.map((pokemon) => (
        <p key={pokemon.id} style={{ color: \"blue\" }}>
          {pokemon.name}
        </p>
      ))}
    </div>
  );
};

export default App;

非常感谢您提前。

  • 这可能是因为您的 getPokeType 方法是异步的,这会导致反应生命周期发挥作用。试试这个const datas = await Promise.all( data.results.map((pokemon) =&gt; axios.get(pokemon.url)) ); setPokemons(datas); 而不是data.results.map((pokemon) =&gt; getPokeType(pokemon));
  • 正如 Marko 所提到的,这是一个小的重构,可以提供您想要的效果。然后,您可以在最后只设置一次状态,无论如何这更干净。 codesandbox.io/s/stoic-leavitt-ngokv9

标签: javascript reactjs


【解决方案1】:

您的问题是您在getPokeType 内调用setPokemons(部分为每个数据调用)。您的 useEffect 只被调用一次(如预期的那样),${BASE_URL}/pokemon 调用也只执行一次。但是getPokeType 被调用了 20 次,pokemons 状态也被更改了 20 次(data.results 中的每个实例一次)。

在您的情况下,我建议(而不是您现在拥有的)是:

  1. 创建所有口袋妖怪的列表和
  2. 最后只设置一次状态。

    所以像:

      ...
    
      const getPokeType = async (pokemon) => {
        const { data } = await axios.get(pokemon.url);
        return data;
      };
      const getAllPokemons = async () => {
        const { data } = await axios.get(`${BASE_URL}/pokemon`);
        const pokemons = await Promise.all(
          data.results.map((pokemon) => getPokeType(pokemon))
        );
        setPokemons(pokemons);
      };
    
      React.useEffect(() => {
        getAllPokemons();
      }, []);
      ...
    

【讨论】:

  • 需要注意的是,因为 Codesandbox react 运行在严格模式下,组件实际上至少渲染了两次——因为他也将先前的状态与新状态连接起来,这导致了 20 多个项目的构建。另外由于键冲突,我相信它会触发更多的重新渲染,有一次我看到当前状态下多达 75 个项目。
【解决方案2】:

我只是在我的项目中遇到了同样的问题,我解决的方法是在 useEffect 中移动函数定义

     React.useEffect(() => {
             const getAllPokemons = async () => {
             const { data } = await axios.get(`${BASE_URL}/pokemon`);

             data.results.map((pokemon) => getPokeType(pokemon));
         };
      getAllPokemons();
     }, []); 

如果这解决了您的问题,请接受答案。

【讨论】:

    猜你喜欢
    • 2022-08-03
    • 2021-10-16
    • 1970-01-01
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-25
    相关资源
    最近更新 更多