perf(cuesheet): revert lazy-autosize (Exp B) — metrics show it regresses

Measured baseline vs lazy-autosize at CPU 4x (median of 3, ~1140 row mounts):
- cell.autosize eliminated (15.2s -> 0) BUT
- EventRow.mount avg +39% (179 -> 248ms), longtask +32%, longFrames 201->219,
  and per-row re-renders ~2x (getVisibleCells renders 4648 -> 8902).
Deferring autosize destabilises virtuoso row-height measurement (rows=1
textareas), causing more re-render churn, and collapses note display.
Net negative — not merged. Keeping instrumented baseline.
This commit is contained in:
Claude
2026-06-15 20:59:33 +00:00
parent a0d72d1776
commit 7498abb326
@@ -1,6 +1,6 @@
// @ts-expect-error no types from library
import autosize from 'autosize/dist/autosize';
import { FocusEvent, RefObject, useCallback, useEffect } from 'react';
import { RefObject, useEffect } from 'react';
import { timeSync } from '../../../devtools/cuesheet-metrics/usePerfMark'; // PERF-METRICS
import Textarea, { type TextareaProps } from '../textarea/Textarea';
@@ -10,41 +10,18 @@ interface AutoTextAreaProps extends TextareaProps {
}
/**
* A textarea that automatically resizes based on its content.
*
* `autosize()` forces a synchronous reflow (reads scrollHeight) and installs a MutationObserver.
* Doing that on mount makes it expensive when many of these are mounted at once (e.g. virtualised
* table rows during scroll), so we only attach autosize while the field is focused for editing and
* keep it in sync with the value during that time.
* A textarea that automatically resizes based on its content
*/
export function AutoTextarea({ value, inputref, onFocus, onBlur, ...textAreaProps }: AutoTextAreaProps) {
const handleFocus = useCallback(
(event: FocusEvent<HTMLTextAreaElement>) => {
timeSync('cell.autosize', () => autosize(inputref.current)); // PERF-METRICS
onFocus?.(event);
},
[inputref, onFocus],
);
const handleBlur = useCallback(
(event: FocusEvent<HTMLTextAreaElement>) => {
if (inputref.current) {
autosize.destroy(inputref.current);
}
onBlur?.(event);
},
[inputref, onBlur],
);
// while focused, keep the height in sync as the value changes
export function AutoTextarea({ value, inputref, ...textAreaProps }: AutoTextAreaProps) {
// when the value changes, we use the ref to reapply autosize
useEffect(() => {
const node = inputref.current;
if (node && document.activeElement === node) {
autosize(node);
}
timeSync('cell.autosize', () => autosize(inputref.current)); // PERF-METRICS
return () => {
autosize.destroy(node);
};
}, [inputref, value]);
return (
<Textarea ref={inputref} value={value} onFocus={handleFocus} onBlur={handleBlur} {...textAreaProps} />
);
return <Textarea ref={inputref} value={value} {...textAreaProps} />;
}