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
相关产品推荐
相关产品推荐

