使用react-countup渲染API数据计数组件无显示问题求助
React-Countup 计数不显示问题的修复方案
核心问题分析
- 手动调用
update方法时,状态更新是异步的,导致获取的是旧状态的长度(比如admins.length在setAdmins后还是旧值) useCountUp初始化时的end值是初始空数组的长度0,后续状态更新后没有重新触发countUp的更新逻辑- 第一个
useEffect中调用userCountUp.update(realData.length)时,realData还没被API返回的结果更新,所以值为0
修复方案
1. 简化状态管理,用派生值替代冗余状态
admins和disabledUsers不需要单独作为状态,直接从realData实时派生,减少状态更新的复杂度:
// 移除原有的两个状态声明 // const [admins, setAdmins] = useState([]) // const [disabledUsers, setDisabledUsers] = useState([]) // 直接在组件内生成派生值 const admins = realData.filter(user => user[6]) const disabledUsers = realData.filter(user => !user[7])
2. 改用组件式写法(推荐)
放弃手动管理useCountUp钩子和ref,直接使用<CountUp>组件,自动响应数据变化:
// 导入组件 import CountUp from 'react-countup' // 在JSX中替换原有的span标签 <div> <h2 className='metric'> <CountUp end={realData.length} start={0} duration={2} /> </h2> <p>Users</p> </div> <div> <h2 className='metric'> <CountUp end={admins.length} start={0} duration={2} /> </h2> <p>Administrators</p> </div> <div> <h2 className='metric'> <CountUp end={disabledUsers.length} start={0} duration={2} /> </h2> <p>Disabled</p> </div>
3. 修正API请求的Effect逻辑
移除多余的Effect,只保留组件挂载时的API请求:
useEffect(() => { listUsers().then(users => { setRealData(users) }).catch(err => { console.log(JSON.stringify(err)) setShouldThrowError(true) }) }, []) // 空依赖确保只执行一次
完整修正代码
import React, { useState, useEffect } from 'react' import CountUp from 'react-countup' import { Grid, Column, Table, TableHead, TableRow, TableHeader, TableBody, TableCell } from 'carbon-components-react' import { listUsers } from './your-api-module' // 替换为你的实际API导入路径 export default function LandingPage() { const [realData, setRealData] = useState([]) const [shouldThrowError, setShouldThrowError] = useState(false) useEffect(() => { listUsers().then(users => { setRealData(users) }).catch(err => { console.log(JSON.stringify(err)) setShouldThrowError(true) }) }, []) // 实时派生用户分类数据 const admins = realData.filter(user => user[6]) const disabledUsers = realData.filter(user => !user[7]) const ErrorBoundary = ({ trigger, fallback, children }) => { if (trigger) { console.log('fallback') return fallback } else { return children } } return ( <> <ErrorBoundary trigger={shouldThrowError} fallback={<h1>An error has occurred</h1>}> <Grid className="dashboard-page" fullWidth> <Column lg={16} md={8} sm={4} className="dashboard-page__banner"> <h1>Admin Dashboard</h1> </Column> <Column className='mt-6 mb-4' lg={16} md={8} sm={4}> <div className='grid grid-cols-3 gap-4 mt-4'> <div> <h2 className='metric'> <CountUp end={realData.length} start={0} duration={2} /> </h2> <p>Users</p> </div> <div> <h2 className='metric'> <CountUp end={admins.length} start={0} duration={2} /> </h2> <p>Administrators</p> </div> <div> <h2 className='metric'> <CountUp end={disabledUsers.length} start={0} duration={2} /> </h2> <p>Disabled</p> </div> </div> </Column> <Column className='mt-6 mb-4' lg={16} md={8} sm={4}> <h2 className='mb-2'>Administrators</h2> <Table> <TableHead> <TableRow> <TableHeader>Last Name</TableHeader> <TableHeader>First Name</TableHeader> <TableHeader>Username</TableHeader> </TableRow> </TableHead> <TableBody> {admins.map(user => ( <TableRow key={user[0]}> <TableCell>{user[5]}</TableCell> <TableCell>{user[4]}</TableCell> <TableCell>{user[1]}</TableCell> </TableRow> ))} </TableBody> </Table> </Column> <Column className='mt-6 mb-4' lg={16} md={8} sm={4}> <h2 className='mb-2'>Disabled</h2> <Table> <TableHead> <TableRow> <TableHeader>Last Name</TableHeader> <TableHeader>First Name</TableHeader> <TableHeader>Username</TableHeader> </TableRow> </TableHead> <TableBody> {disabledUsers.map(user => ( <TableRow key={user[0]}> <TableCell>{user[5]}</TableCell> <TableCell>{user[4]}</TableCell> <TableCell>{user[1]}</TableCell> </TableRow> ))} </TableBody> </Table> </Column> </Grid> </ErrorBoundary> </> ); }
关键修改说明
- 移除冗余状态,用实时派生值避免异步更新问题
- 组件式写法自动响应数据变化,无需手动管理ref和update
- 简化API请求逻辑,避免无效的状态更新触发
- 添加
duration参数控制计数动画时长,优化用户体验
内容的提问来源于stack exchange,提问作者code writer 3000
相关产品推荐
相关产品推荐

