chore: clean up

This commit is contained in:
2026-11-04 08:57:07 +07:00
parent ded23ab2f2
commit fa73124ee4
5 changed files with 161 additions and 19 deletions
+4 -1
View File
@@ -66,7 +66,10 @@ GPUI is a UI framework which also provides primitives for state and concurrency
- Keep `render` declarative; use `.when(...)` / `.when_some(...)` for small conditional refinements.
- Controlled components: the owner passes the current value, callbacks report intent, the owner updates state and calls `cx.notify()`. No second source of truth.
- Call `cx.notify()` after a mutation that changes rendering; notify the narrowest owning entity. Never notify from `render`.
- Use `cx.emit(...)` for semantic events (declare `impl EventEmitter<EventType>`), `cx.subscribe(...)` / `cx.observe(...)` for reactions, and store returned `Subscription`s in the owner (commonly `_subscriptions: Vec<Subscription>`).
- `render` is side-effect free: no `cx.notify()`, no `entity.update(...)`, no writing derived text or state back into other entities during render. A write there forces another frame, and a write that emits an event re-enters the event handler — an unbounded redraw loop. Reconcile state in event handlers instead, with silent setters (`set_value_silent`-style) so a control's own write does not re-enter the events it mirrors.
- Use `cx.emit(...)` for semantic events (declare `impl EventEmitter<EventType>`), `cx.subscribe(...)` / `cx.observe(...)` for reactions, and store returned `Subscription`s in the owner (commonly `_subscriptions: Vec<Subscription>`). Never `.detach()` a component's own subscription — detached subscriptions outlive the component and fire into dropped state; detach is only for app-lifetime wiring registered once at startup.
- To take a key a focused child has already bound, add bindings in a deeper context (`"Parent > Child"` predicate) registered after the child's — gpui breaks equal-depth ties by later registration. Do not intercept keystrokes globally for component-scoped keys; an interceptor runs for every keystroke in every window.
- Animations schedule frames that re-render the whole window. Continuous animations (`repeat()`) must cap their frame rate (`with_max_fps`); skip entry animations on surfaces that redraw with typing (popups over text fields), where each frame is a full window redraw.
- Use stable domain-derived `ElementId`s (`("delete-project", project.id)`); never list indexes or freshly generated random IDs for reorderable content.
- `cx.listener(...)` adapts event handlers to update the current entity.
- Actions: `actions!(namespace, [Action])` for data-free actions, the `Action` derive otherwise; register `on_action` on the focused region with a matching `key_context`.