
本文介绍如何将嵌套的日期-类别数据结构转换为「类别为行、日期为列」的响应式 html 表格,通过 `reduce` 预处理数据 + `map` 渲染,实现跨时间维度的横向对比展示。
要实现目标表格结构——即每类资产(如 Criptomoedas、REITs)作为独立行,各日期作为列头,对应金额横向对齐显示——关键在于重构原始数据形态:原始 category_evolution 是「按日期分组 → 每组含多个类别」,而表格渲染需要「按类别分组 → 每类含多个日期值」。
✅ 正确的数据预处理逻辑
我们需将分散在不同日期对象中的同类目数据聚合起来。推荐使用两次 reduce:
- 扁平化所有条目:合并所有 data 数组;
- 按 category 分组索引:构建以类别名为键、该类别在各日期下的数据数组为值的对象(确保顺序与 category_evolution 中日期顺序一致)。
// 假设 category_evolution 已通过 useEffect + fetch 加载完成
const categoryMap = category_evolution.reduce((acc, { data }) => {
data.forEach(item => {
if (!acc[item.category]) {
acc[item.category] = [];
}
acc[item.category].push(item);
});
return acc;
}, {} as Record); ✅ 优势:无需预先知道类别名或日期数量;天然保持 category_evolution 的日期顺序;支持任意长度的时间序列。
✅ 动态渲染表格主体(tbody)
利用 Object.keys(categoryMap) 获取唯一类别列表,并为每个类别生成一行
{Object.keys(categoryMap).map(category => (
{category}
{categoryMap[category].map((item, idx) => (
{item.category_total_brl}
))}
))}
⚠️ 注意:此处依赖 categoryMap[category] 数组内元素顺序与 category_evolution 原始顺序严格一致(由 reduce 遍历顺序保证),因此无需额外排序。
✅ 完整可运行 JSX 示例
| Categoria | {category_evolution.map(({ name }) => ({name} | ))}
|---|---|
| {category} | {categoryMap[category].map((item, idx) => ({item.category_total_brl} | ))}
? 补充说明与健壮性建议
-
空数据兜底:若某类别在某日期缺失,categoryMap[category] 对应位置可能为空。可在渲染时添加 ?. 或默认值:
{item?.category_total_brl ?? '—'} - 类型安全(TypeScript):建议为 category_evolution 定义接口,避免运行时属性访问错误;
- 性能优化:若数据量极大(>1000 行),可考虑 React.memo 包裹表格组件或虚拟滚动;
-
扩展性提示:如需同时展示 BRL 和 USD 列,只需在
中增加一列,或改用嵌套 结构。BRLUSD
通过这种「先归类、再映射」的思路,你不仅能精准实现需求中的横向对比表,还能轻松适配未来新增日期或类别的动态场景。










