Skip to content

ui: extract a shared useStableReference(value, eqFn) hook for render-phase reference stability #578

Description

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions