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

React中统计Bug状态/严重度计数 避免无限循环的实现方法

问题原因

你之前触发无限循环,本质是几个常见的低级错误:

  • 直接在组件渲染顶层(没有被useEffect、事件回调包裹的位置)调用setCounts,每次setState触发组件重渲染,重渲染又执行setState,形成死循环
  • 配置统计逻辑的useEffect时错误把counts加入依赖数组,每次setCounts更新counts后触发effect再次执行,再次setCounts形成循环
  • 额外维护派生状态本身就容易出现数据不同步问题,这类从已有state(allBugs)计算得到的值,根本不需要单独用useState存储。
推荐实现方案(无额外state,无循环问题)

直接用useMemo基于allBugs派生计算counts,只有当allBugs变化时才会重新执行统计,不会触发额外重渲染,也不会出现状态不同步。

完整组件逻辑

import { useSelector, useDispatch } from 'react-redux';
import { useEffect, useMemo } from 'react';
// 其他业务依赖导入:findAllBugServer、DashboardStateCard、页面方法等

const DashboardPage = () => {
  const {allBugs} = useSelector((store) => store.bug);
  const dispatch = useDispatch();

  // 自动统计bug数据
  const counts = useMemo(() => {
    // 初始化计数字段
    const defaultCounts = {
      open: 0,
      toBeTested: 0,
      inProgress: 0,
      closed: 0,
      minor: 0,
      major: 0,
      critical: 0,
      showStopper: 0
    }
    // 接口未返回有效数据时直接返回默认值
    if (!Array.isArray(allBugs)) return defaultCounts;

    return allBugs.reduce((stats, bug) => {
      // 按状态维度统计
      switch(bug.status) {
        case 'open': stats.open++; break;
        case 'toBeTested': stats.toBeTested++; break;
        case 'inProgress': stats.inProgress++; break;
        case 'closed': stats.closed++; break;
      }
      // 按严重程度维度统计
      switch(bug.severity) {
        case 'minor': stats.minor++; break;
        case 'major': stats.major++; break;
        case 'critical': stats.critical++; break;
        case 'showStopper': stats.showStopper++; break;
      }
      return stats;
    }, defaultCounts)
  }, [allBugs])

  // 页面初始化逻辑
  useEffect(() => {
    dispatch(findAllBugServer());
    handleSidenavOpenDashboardPage();
    handleSidenavOpen();
  }, [dispatch, handleSidenavOpenDashboardPage, handleSidenavOpen])

  // 页面渲染
  return (
    <div className="dashboard-container">
      {/* 其他页面业务组件 */}
      <div className="state-card-group">
        <DashboardStateCard name={"Open"} count={counts.open} />
        <DashboardStateCard name={"To Be Tested"} count={counts.toBeTested} />
        <DashboardStateCard name={"In Progress"} count={counts.inProgress} />
        <DashboardStateCard name={"Closed"} count={counts.closed} />
        <DashboardStateCard name={"Minor"} count={counts.minor} />
        <DashboardStateCard name={"Major"} count={counts.major} />
        <DashboardStateCard name={"Critical"} count={counts.critical} />
        <DashboardStateCard name={"Show Stopper"} count={counts.showStopper} />
      </div>
    </div>
  )
}

export default DashboardPage;
注意事项
  • 统计时请核对接口返回的status、severity字段实际取值,如果返回值是下划线命名(比如in_progress、show_stopper),需要对应修改switch的判断条件,避免统计值恒为0的问题
  • 如果一定要保留useState的写法,需要把统计逻辑放在useEffect中,且依赖数组仅传入allBugs,不要把counts加入依赖,否则会再次触发无限循环。该方案不推荐,因为容易出现allBugs更新后counts未同步的脏数据问题。
  • 不要在组件渲染的顶层位置直接调用任何setState函数,会直接触发重渲染死循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:21:18