React中useMemo的使用

代码示例

javascript 复制代码
// 导入 React 和必要的 Hooks
import React, { FC, useMemo } from 'react'

// 从 recharts 库导入图表组件
import { 
  PieChart,         // 饼图容器
  Pie,              // 饼图主体
  Cell,             // 饼图的每一个扇形"单元格"
  Tooltip,          // 提示框(鼠标悬停时显示详细数值)
  ResponsiveContainer // 响应式容器,使图表能自适应父容器大小
} from 'recharts'

// 导入预定义的颜色常量数组,用于给不同的饼图扇形分配颜色
import { STAT_COLORS } from '../../../constant'

// 导入该组件所需的 Props 类型定义
import { QuestionRadioStatPropsType } from './interface'

/**
 * 格式化数字工具函数
 * 将小数转换为保留两位的百分比数值(字符串)
 * 
 * @example 0.1234 -> "12.34"
 */
function format(n: number) {
  return (n * 100).toFixed(2)
}

/**
 * 单选题统计图表组件
 * 
 * 该组件接收统计数据,计算总和,并渲染一个带有百分比标签和颜色区分的饼图。
 */
const StatComponent: FC<QuestionRadioStatPropsType> = ({ stat = [] }) => {
  
  // --- 计算总和 (使用 useMemo 进行性能优化) ---
  // 依赖项 [stat]:只有当 stat 数据变化时,才重新计算总和
  // 如果不使用 useMemo,组件每次重新渲染都会执行一次 forEach 循环,浪费性能
  const sum = useMemo(() => {
    let s = 0
    stat.forEach(i => (s += i.count))
    return s
  }, [stat])

  return (
    // 外层容器设置了固定的宽高 (300x400),作为图表的宿主
    <div style=>
      
      {/* 
        响应式容器,包裹图表。
        width="100%" height="100%" 表示图表将填满父容器。
      */}
      <ResponsiveContainer width="100%" height="100%">
        
        {/* 饼图根组件 */}
        <PieChart>
          
          {/* 
            Pie 组件:定义具体的饼图数据和样式
            dataKey="count": 指定数据对象中哪个字段决定扇形的大小(占比)
            data={stat}: 绑定传入的统计数据数组
            cx="50%" / cy="50%": 设置饼图在容器中的中心位置(水平垂直居中)
            outerRadius={50}: 设置饼图的外半径大小(单位:px)
            fill="#8884d8": 设置默认填充色(如果 Cell 没有指定颜色,会使用这个)
            
            label: 定义扇形上的标签内容
              接收一个函数,参数 i 代表当前扇形对应的数据项
              返回字符串:例如 "选项A: 50.00%"
          */}
          <Pie
            dataKey="count"
            data={stat}
            cx="50%"
            cy="50%"
            outerRadius={50}
            fill="#8884d8"
            label={i => `${i.name}: ${format(i.count / sum)}%`}
          >
            
            {/* 
              动态渲染扇形颜色
              遍历 stat 数据,为每一个数据项生成一个 <Cell>
              Cell 用于定义每一个扇形的具体样式(主要是 fill 颜色)
              使用 STAT_COLORS[index] 从预定义的颜色数组中按索引取色
              key={index}:虽然不推荐仅用 index 作为 key,但在这里图表渲染是合理的
            */}
            {stat.map((i, index) => {
              return <Cell key={index} fill={STAT_COLORS[index]} />
            })}
            
          </Pie>
          
          {/* 鼠标悬停提示框 */}
          <Tooltip />
          
        </PieChart>
      </ResponsiveContainer>
    </div>
  )
}

export default StatComponent

核心逻辑解析

💡 核心逻辑解析

1. useMemo 的作用
  • 场景: 计算所有选项的总票数(sum)。
  • 原因: 如果 stat 数组很大,或者计算逻辑很复杂,每次组件渲染都重新计算会浪费性能。
  • 效果: useMemo 确保只有当 stat 数据真正发生变化时,才重新执行 forEach 循环去累加求和。如果 stat 没变,直接复用上一次计算的结果。
2. label 回调函数
  • label 属性允许你自定义扇形上的文字。
  • i.count / sum 计算出当前选项的占比(小数)。
  • format(...) 将小数转换为保留两位的百分比字符串。
  • 最终显示效果类似:A: 25.00%
3. <Cell> 的作用
  • <Pie> 标签上的 fill 属性是设置"默认颜色"。
  • <Cell> 标签用于给每一个独立的扇形设置颜色。
  • 代码中通过 stat.map 遍历数据,将预定义的颜色数组 STAT_COLORS 中的颜色依次分配给每个选项,从而实现多彩饼图的效果。
相关推荐
灵感__idea1 小时前
Hello 算法:贪心的世界
前端·javascript·算法
GreenTea3 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
killerbasd4 小时前
牧苏苏传 我不装了 4/7
前端·javascript·vue.js
吴声子夜歌4 小时前
ES6——二进制数组详解
前端·ecmascript·es6
码事漫谈5 小时前
手把手带你部署本地模型,让你Token自由(小白专属)
前端·后端
ZC跨境爬虫5 小时前
【爬虫实战对比】Requests vs Scrapy 笔趣阁小说爬虫,从单线程到高效并发的全方位升级
前端·爬虫·scrapy·html
爱上好庆祝5 小时前
svg图片
前端·css·学习·html·css3
橘子编程5 小时前
JavaScript与TypeScript终极指南
javascript·ubuntu·typescript
王夏奇5 小时前
python中的__all__ 具体用法
java·前端·python
叫我一声阿雷吧6 小时前
JS 入门通关手册(45):浏览器渲染原理与重绘重排(性能优化核心,面试必考
javascript·前端面试·前端性能优化·浏览器渲染·浏览器渲染原理,重排重绘·reflow·repaint