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

使用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>
    </>
  );
}

关键修改说明

  1. 移除冗余状态,用实时派生值避免异步更新问题
  2. 组件式写法自动响应数据变化,无需手动管理ref和update
  3. 简化API请求逻辑,避免无效的状态更新触发
  4. 添加duration参数控制计数动画时长,优化用户体验

内容的提问来源于stack exchange,提问作者code writer 3000

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 15:17:04