You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React严格模式下useState存储宝可梦类型出现重复的解决方法

解决React严格模式下宝可梦类型数组重复的问题

问题根源

React严格模式在开发环境中会重复执行useEffect等生命周期逻辑,目的是帮你排查潜在的代码问题。你的代码里每次useEffect执行都会触发18次接口请求,每次请求完成后都往状态数组里追加数据,两次执行就导致了36条重复数据。

最优解决方案:一次性获取所有类型

PokeAPI本身提供了获取全量类型列表的接口,无需循环调用单个类型接口,一次请求就能拿到所有数据,从根源避免重复问题:

function App() {
  const [types, setTypes] = useState([]);

  useEffect(() => {
    const fetchAllTypes = async () => {
      try {
        const res = await axios.get('https://pokeapi.co/api/v2/type/');
        // 从返回结果中提取所有类型名称
        const typeNames = res.data.results.map(item => item.name);
        setTypes(typeNames);
      } catch (error) {
        console.log(error);
      }
    };

    fetchAllTypes();
  }, []);

  return (
    // ...你的组件内容
  );
}

这个方案不仅解决了重复问题,还把18次请求压缩为1次,性能更优。

若坚持循环单个请求的解决办法

如果一定要保留循环调用单个类型接口的逻辑,可以通过以下两种方式避免重复:

方式1:用useRef标记是否已完成请求

用useRef存储一个布尔值,标记是否已经发起过请求,第二次useEffect执行时直接跳过:

function App() {
  const [types, setTypes] = useState([]);
  const hasFetched = useRef(false); // 标记是否已发起过请求

  useEffect(() => {
    if (hasFetched.current) return; // 已请求过则直接返回
    hasFetched.current = true;

    const fetchType = async (typeId) => {
      try {
        const res = await axios.get(`https://pokeapi.co/api/v2/type/${typeId}`);
        setTypes(prev => [...prev, res.data.name]);
      } catch (error) {
        console.log(error);
      }
    };

    for (let i = 1; i <= 18; i++) {
      fetchType(i);
    }
  }, []);

  return (
    // ...你的组件内容
  );
}

方式2:并行请求后一次性更新状态

用Promise.all等待所有请求完成后再统一设置状态,同时通过判断状态数组是否已有数据,避免重复更新:

function App() {
  const [types, setTypes] = useState([]);

  useEffect(() => {
    if (types.length > 0) return; // 已有数据则跳过

    const fetchAllTypes = async () => {
      try {
        // 创建所有请求的Promise数组
        const requests = Array.from({ length: 18 }, (_, idx) => 
          axios.get(`https://pokeapi.co/api/v2/type/${idx + 1}`)
        );
        // 等待所有请求完成
        const responses = await Promise.all(requests);
        // 提取所有类型名称
        const typeNames = responses.map(res => res.data.name);
        setTypes(typeNames);
      } catch (error) {
        console.log(error);
      }
    };

    fetchAllTypes();
  }, [types]);

  return (
    // ...你的组件内容
  );
}

注意:这种方式在开发环境下还是会触发两次共36个请求,只是第二次会因为状态已有数据而跳过更新,因此更推荐用一次性请求的方案。

内容的提问来源于stack exchange,提问作者Keitaro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:47:42