--- sidebar_position: 1 title: The Component Model --- # The Component Model At the core of OSUI's design is a robust component model, defining how UI elements are created, composed, and managed. This model provides structure, promotes reusability, and facilitates a clear separation of concerns within your TUI application. ## `ComponentImpl`: The Building Block The `ComponentImpl` trait is the most fundamental concept for any renderable unit in OSUI: ```rust pub trait ComponentImpl: Send + Sync { /// Renders the component within the given context, returning a View fn call(&self, cx: &Arc) -> View; } ``` * **`fn call(&self, cx: &Arc) -> View`**: This method is where a component's rendering logic resides. It takes a reference to the component instance itself and its `Context` (`cx`), and it must return a `View`. The `View` is OSUI's abstraction for "what to draw," essentially a closure that will populate a `DrawContext` with drawing instructions later in the rendering pipeline. * **`Send + Sync`**: Components must be `Send` and `Sync` to ensure they can be safely passed between threads, as OSUI leverages concurrency for various operations (e.g., `use_effect` hooks). Most often, you won't implement `ComponentImpl` manually. Instead, you'll use the `#[component]` procedural macro: ```rust #[component] fn MyComponent(cx: &Arc, some_prop: &String) -> View { // Component logic and RSX here rsx! { format!("Prop: {}", some_prop) }.view(&cx) } ``` The `#[component]` macro automatically generates a struct for `MyComponent` (with `some_prop: String` as a field) and implements `ComponentImpl` for it, delegating the `call` method to your function's body. ## `Context`: The Component's Identity and State Every active instance of a component in the UI tree has its own `Context` (`osui::component::context::Context`). The `Context` is the component's runtime identity and central hub for managing its internal state and interactions: ```rust pub struct Context { component: AccessCell, view: AccessCell, event_handlers: AccessCell>>, pub(crate) scopes: Mutex>>, executor: Arc, } ``` **Why `Context` is crucial**: * **State Management**: It's the entry point for all state hooks (`use_state`, `use_effect`, etc.), ensuring that each component instance manages its own isolated, reactive state. * **Event Handling**: `Context` provides methods (`on_event`, `emit_event`) for handling component-specific and application-wide events. Events propagate through the `Context` tree. * **Rendering Result (`View`)**: It holds the `View` generated by the `ComponentImpl::call` method, which is later passed to the rendering engine. * **Child Management (`scopes`)**: A `Context` aggregates child components through `Scope`s, forming the hierarchical UI tree. * **Engine Interaction**: It provides access to the `CommandExecutor`, allowing components to send commands (like `Stop`) to the underlying engine. When a component is instantiated (e.g., `MyComponent { ... }` in `rsx!`), a new `Context` is created for it. This `Context` lives as long as the component is part of the active UI tree. ## `Scope`: Organizing Children While `Context` represents a single component instance, `Scope` (`osui::component::scope::Scope`) is responsible for grouping and managing collections of child `Context`s: ```rust pub struct Scope { pub children: Mutex, Option)>>, executor: Arc, } ``` **Relationship between `Context` and `Scope`**: * A `Context` can contain multiple child `Scope`s (stored in `Context::scopes`). * Each `Scope` then contains a `Vec` of `(Arc, Option)`, representing the actual child components (and optional view modifiers) within that specific scope. * This distinction allows for flexibility in how children are managed, particularly for dynamic `rsx!` constructs like `@if` and `@for` which might create or destroy entire `Scope`s based on conditions or iterations. **How `Scope`s are used**: * When you use `rsx!`, the macro emits calls to `context.scope()` or `context.dyn_scope()`, which create new `Scope`s. * Within these `Scope`s, children are added using `scope.child()` or `scope.view()`. * The `Context::draw_children` method then iterates through these `Scope`s and their children to orchestrate their rendering. ## The Component Tree Together, `ComponentImpl`, `Context`, and `Scope` form a hierarchical component tree: ``` App Component (Context) └── App Scope (from App's rsx!) ├── Child Component A (Context) │ └── Child A Scope (from A's rsx!) │ └── Grandchild Component X (Context) ├── Child Component B (Context) │ └── Child B Scope │ ├── Grandchild Component Y (Context) │ └── Grandchild Component Z (Context) └── Dynamic Scope (e.g., from an `@if` block) └── (Conditionally rendered children) ``` This tree structure is fundamental to OSUI's rendering and event propagation. Events emitted by a child `Context` can traverse up the tree to parent `Context`s (if they listen for them) and always propagate down to all descendants. The component model provides a clear, organized, and powerful way to structure your TUI applications, promoting maintainability and scalability through modularity and a well-defined lifecycle for each UI element. **Next:** Understand how `State` and `HookDependency` enable efficient UI updates in [Reactive State Flow](./02-reactive-state-flow.md).