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

React中console.count多次执行的原因排查求助

组件频繁刷新(console.count()触发12次)的原因及优化

问题描述

在组件的useEffect下方使用console.count(),发现它被调用了12次,想明确频繁刷新的原因,以及是否和定义的多个state有关。

组件代码如下:

const { user } = UserAuth();
const { id } = useParams()
const [count, setCount] = useState(() => { return id ? parseInt(id) : 5 })
const [name, setName] = useState()
const [img, setImg] = useState()
const [stats, setStats] = useState()
const [types, setTypes] = useState()
const [otherStats, setOtherStats] = useState()
const [desc, setDesc] = useState()
const [favoritePokemon, setFavoritePokemon] = useState()
const navigate = useNavigate()
const location = useLocation()

useEffect(() => {
    navigate(`/PokemonPage/${count}`)
    fetch('https://pokeapi.co/api/v2/pokemon/' + count)
        .then(res => {
            if (res.status >= 400) {
                return setCount(1)
            }
            return res.json()
        })
        .then(data => {
            setName(data.name)
            setImg(data.sprites.front_default)
            setTypes(data.types)
            setStats(data.stats)
            fetch(data.species.url)
                .then(res => res.json())
                .then(speciesData => {
                    setDesc(speciesData.flavor_text_entries[4])
                    setOtherStats({ "height": data.height, "weight": data.weight, "base_happiness": speciesData.base_happiness, "capture_rate": speciesData.capture_rate })
                })
        })
}, [count])

console.count()

原因分析

组件频繁刷新和多个state定义、当前代码逻辑都有关系,具体拆解:

  • 多state更新触发多次重渲染:每次调用setName、setImg、setTypes、setStats、setDesc、setOtherStats这些setState方法,都会单独触发组件重渲染。一次完整请求下来,你先后调用了6次setState,这就会带来6次重渲染(React在某些场景下不会自动合并更新)。
  • useEffect的循环触发:useEffect依赖count,当count变化时会执行逻辑;而navigate(/PokemonPage/${count})会修改路由,路由参数id变化又会触发useParams()更新,进而触发组件重渲染。如果请求返回400+状态码,setCount(1)会再次触发useEffect执行,形成一轮新的更新循环。
  • 其他潜在触发源:UserAuth()返回的user如果在渲染过程中发生变化,也会触发组件重渲染;组件首次挂载本身也会触发一次初始渲染。

优化方案

  1. 合并state更新:将分散的state合并为一个对象,减少setState调用次数,从而减少重渲染:
const [pokemonData, setPokemonData] = useState({
  name: '',
  img: '',
  types: [],
  stats: [],
  desc: '',
  otherStats: {}
});

// 请求成功后一次性更新所有数据
setPokemonData({
  name: data.name,
  img: data.sprites.front_default,
  types: data.types,
  stats: data.stats,
  desc: speciesData.flavor_text_entries[4],
  otherStats: {
    height: data.height,
    weight: data.weight,
    base_happiness: speciesData.base_happiness,
    capture_rate: speciesData.capture_rate
  }
});
  1. 避免不必要的路由跳转:添加判断,仅当当前路由不匹配时才执行navigate,防止重复触发路由更新:
if (location.pathname !== `/PokemonPage/${count}`) {
  navigate(`/PokemonPage/${count}`);
}
  1. 添加请求清理逻辑:在useEffect中使用AbortController,防止组件卸载后请求仍在执行,避免无效的setState触发重渲染:
useEffect(() => {
  const abortController = new AbortController();
  
  const fetchPokemon = async () => {
    try {
      const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${count}`, { signal: abortController.signal });
      if (res.status >= 400) {
        setCount(1);
        return;
      }
      const data = await res.json();
      const speciesRes = await fetch(data.species.url, { signal: abortController.signal });
      const speciesData = await speciesRes.json();
      
      setPokemonData({
        name: data.name,
        img: data.sprites.front_default,
        types: data.types,
        stats: data.stats,
        desc: speciesData.flavor_text_entries[4],
        otherStats: {
          height: data.height,
          weight: data.weight,
          base_happiness: speciesData.base_happiness,
          capture_rate: speciesData.capture_rate
        }
      });

      if (location.pathname !== `/PokemonPage/${count}`) {
        navigate(`/PokemonPage/${count}`);
      }
    } catch (err) {
      if (err.name !== 'AbortError') {
        console.error('请求失败:', err);
      }
    }
  };

  fetchPokemon();
  return () => abortController.abort(); // 组件卸载时终止请求
}, [count, location.pathname, navigate]);
  1. 检查UserAuth的稳定性:确认UserAuth()返回的user对象不会每次渲染都生成新引用,必要时用useMemo包裹或调整Auth库的使用方式,避免因user变化触发无意义的重渲染。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 09:47:05