diff --git a/src/pages/Transactions.tsx b/src/pages/Transactions.tsx index 1b0acd48..16626544 100644 --- a/src/pages/Transactions.tsx +++ b/src/pages/Transactions.tsx @@ -76,6 +76,31 @@ export default function Transactions() { [visibleTransactions, filter] ) + /** + * Memoized data transformer: pre-computes formatted display values for + * every visible row so that expensive operations (toLocaleString, Date + * arithmetic, i18n lookups, string truncation) run only when the source + * data or filter changes, not on every render. + */ + interface TableRow extends Transaction { + formattedAmount: string + formattedTime: string + statusBadgeVariant: string + formattedHash: string + } + + const tableRows: TableRow[] = useMemo( + () => + filtered.map((tx) => ({ + ...tx, + formattedAmount: tx.amountUsdc != null ? formatUsdc(tx.amountUsdc) : '\u2014', + formattedTime: relativeTime(tx.timestamp), + statusBadgeVariant: STATUS_BADGE_MAP[tx.status], + formattedHash: truncateAddress(tx.hash), + })), + [filtered] + ) + // Reset transient overlays when the underlying dataset changes (refetch // or unmount between fetches). Stale IDs would otherwise leak selection // into the new list. @@ -328,11 +353,11 @@ export default function Transactions() {
- {filtered.map((tx) => { - const selected = isRowSelected(tx.id) + {tableRows.map((row) => { + const selected = isRowSelected(row.id) return (