Capítulo 39 de 54
rowAggregationFeature is independent of grouping — it works over any row subset (grand totals, filtered totals, a slice you pass in) via column.getAggregationValue(), and only needs columnGroupingFeature + a grouped row model when you specifically want per-group aggregate values on synthetic grouped rows.
aggregationFns: { sum: aggregationFn_sum, ... } — a definition passed directly to a column's aggregationFn needs no registry entry at all. stockFeatures includes rowAggregationFeature but not the named definitions — you still register those explicitly for string references to resolve.aggregationFn accepts one value or an array. One value → scalar result. An array (strings and/or { id, aggregationFn } descriptors for a stable custom key) → an object keyed by name/id. Duplicate or missing descriptor ids and unregistered names warn in dev and leave that key undefined rather than throwing.column.getAggregationValue() with no args aggregates the default pre-grouped row model (filtering applied; grouping/sorting/expansion/pagination don't affect it) — cached against row model + depth + registry + column option. Pass { rows, maxDepth } to aggregate any other row set explicitly (e.g. table.getFilteredSelectedRowModel().rows, a manual .slice()) — explicit calls always recompute, never cached.maxDepth semantics: relative to the supplied row array — 0 = those roots, 1 = their direct children, etc. A branch shallower than maxDepth contributes its deepest available row (a "unique frontier," never skipped entirely); Infinity selects terminal leaf rows. Configure a default via the column's maxAggregationDepth (defaults 0) for the cached no-args call, or override per explicit call. table.getMaxSubRowDepth() gives the deepest structural depth in the core row model — useful to compute "one level above the deepest leaf" (getMaxSubRowDepth() - 1).rowAggregationFeature and columnGroupingFeature + groupedRowModel: createGroupedRowModel(), then set aggregationFn on the columns that should show group totals. Render group-level values via the aggregatedCell column option (checked with cell.getIsAggregated(), which only exists once rowAggregationFeature is registered — a grouping-only table has no such API). Footers render normally through the adapter's usual footer renderer regardless.constructAggregationFn({ aggregate, merge? }): aggregate({ rows, getValue, column, columnId, maxDepth, table, groupingRow?, subRows? }) — rows is the depth-selected unique frontier; groupingRow/subRows only exist during grouped aggregation (root/explicit-row calls omit them). subRows are the group's immediate structural children (data rows at the terminal grouping level, synthetic sub-groups at nested levels) — use them instead of rows when a custom aggregation specifically wants immediate children rather than the depth-selected set.merge for efficient nested aggregation: when provided, nested grouping combines already-computed sub-row results (subRowResults[i] = the result previously computed for subRows[i]) instead of re-running aggregate over the full flattened set at every level — worth adding for anything more expensive than a simple reduce.getAggregationValue({ rows }) => {...} can intercept the request — return { value } (including { value: undefined }) to mark it handled, or undefined to fall through to local computation. Put the same provider on defaultColumn to share it. manualAggregation: true disables the local fallback entirely for column.getAggregationValue() — independent of manualGrouping, which only controls whether the grouped row model itself runs.sum (non-numbers contribute 0), count, min/max (numeric or Date), extent ([min, max], empty input → [undefined, undefined]), mean (numeric/number-like non-null), median (requires every value be a number), unique/uniqueCount (Set semantics), first/last (positional, including nullish). aggregationFn: 'auto' inspects the first core row's value: numbers → sum, dates → extent, anything else → unresolved.column.getAggregationValue() always runs its final total on the main thread over the selected row model — worker-crossing results must be structured-cloneable.const features = tableFeatures({
rowAggregationFeature, columnGroupingFeature,
groupedRowModel: createGroupedRowModel(),
aggregationFns: { sum: aggregationFn_sum, mean: aggregationFn_mean },
})
columnHelper.accessor('visits', {
aggregationFn: 'sum',
aggregatedCell: ({ getValue }) => getValue<number>().toLocaleString(),
footer: ({ column }) => column.getAggregationValue<number>().toLocaleString(), // grand total, ungrouped default
})
columnHelper.accessor('score', {
aggregationFn: ['count', 'mean', { id: 'range', aggregationFn: 'extent' }], // multi-result
})
aggregatedCell (via grouped row model) and a grand-total footer (via the default no-args getAggregationValue()) — two independent uses of one registered sum function.column.getAggregationValue() with no args is cached and grouping-independent; passing explicit { rows } always recomputes — pick deliberately based on how often the subset changes.merge on custom aggregation definitions once nested grouping is involved and the computation isn't a cheap reduce — it avoids re-scanning the same rows at every grouping level.columnGroupingFeature and groupedRowModel, the other half of grouped aggregation.