Follow-up from #575 review.
The UI now has multiple hand-rolled copies of the "keep the previous reference unless render-relevant fields changed" idiom:
pickStableNode + render-time state adjustment in ui/src/views/DesignView.tsx
- the inline
stableSelectedNode ref-cache useMemo in ui/src/views/MonitorView.tsx (~line 276) — same logic with extra compared fields (sessionId, draft); also itself a React Compiler bailout (ref written during render)
entriesEqual + render-time state adjustment in ui/src/nodes/compositorNodeEntries.ts
Each comparator's field list must be kept in sync by hand with the data type and the memo'd consumer's prop usage; nothing links them, so a new render-relevant field added to the data but not the comparator silently yields stale renders.
Proposal: extract a shared useStableReference(value, eqFn) hook (compare-during-render, setState-only-on-change, return-new-value-this-render) and migrate the three sites — fixing MonitorView's compiler bailout in the process. Consider typing comparators against the concrete data types instead of Record<string, unknown> so missing/dead fields are caught by tsc.
Follow-up from #575 review.
The UI now has multiple hand-rolled copies of the "keep the previous reference unless render-relevant fields changed" idiom:
pickStableNode+ render-time state adjustment inui/src/views/DesignView.tsxstableSelectedNoderef-cacheuseMemoinui/src/views/MonitorView.tsx(~line 276) — same logic with extra compared fields (sessionId,draft); also itself a React Compiler bailout (ref written during render)entriesEqual+ render-time state adjustment inui/src/nodes/compositorNodeEntries.tsEach comparator's field list must be kept in sync by hand with the data type and the memo'd consumer's prop usage; nothing links them, so a new render-relevant field added to the data but not the comparator silently yields stale renders.
Proposal: extract a shared
useStableReference(value, eqFn)hook (compare-during-render, setState-only-on-change, return-new-value-this-render) and migrate the three sites — fixing MonitorView's compiler bailout in the process. Consider typing comparators against the concrete data types instead ofRecord<string, unknown>so missing/dead fields are caught by tsc.