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 中的颜色依次分配给每个选项,从而实现多彩饼图的效果。
相关推荐
passerby60613 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了3 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅4 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment4 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax
Cobyte5 小时前
AI全栈实战:使用 Python+LangChain+Vue3 构建一个 LLM 聊天应用
前端·后端·aigc