# Reactivity Module: `src/interpreter/reactive.rs` Dependency tracking system between variables and VDOM elements. Allows recalculation of only changed elements (Phase 3). --- ## `ElementId(u32)` Unique element identifier in the VDOM tree. Assigned by `ReactiveTracker::alloc_id()` during template loading. ```rust #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct ElementId(pub u32); ``` **Used as:** - Key in `dirty_set: HashSet` - Key in `dependencies: HashMap>` - Field in `Element::element_id` (VDOM → tracker link) - Source for `iced::widget::Id` (Phase 9.2: `format!("ti:{}", id.0)`) - Source for scrollable_id (`el.element_id.0 as u64`) --- ## `ReactiveTracker` Dependency graph: variable → list of elements that reference it. ```rust pub struct ReactiveTracker { subscribers: HashMap>, dependencies: HashMap>, dirty_set: HashSet, next_id: u32, } ``` **Fields:** - `subscribers` — for each variable: which ElementIds depend on it - `dependencies` — for each element: which variables it depends on (reverse mapping) - `dirty_set` — elements to recalculate in the next frame - `next_id` — counter for `alloc_id()` ### Methods | Method | Description | |--------|-------------| | `new()` | Empty tracker | | `alloc_id() -> ElementId` | Allocate a new ID, increment counter | | `add_dependency(element, var_name)` | Register a dependency | | `scan_value(element, value)` | Scan a string for `$var` and add dependencies | | `on_variable_changed(name)` | Mark all dependent elements as dirty | | `take_dirty_set() -> HashSet` | Take dirty_set and clear it | | `is_dirty(id) -> bool` | Check if an element is marked dirty | | `reset()` | Clear all data | ### scan_value() Parses a string for `$var_name` patterns: ```rust "Hello $name, you are $age years old" // → add_dependency(element, "name") // → add_dependency(element, "age") ``` Used during template loading for each properties string containing `$`. As a result, each element knows which variables it depends on. ### Update cycle ``` Event → update() → on_variable_changed("var") → dirty_set = {element_A, element_B, ...} → take_dirty_set() → evaluate_vdom_incr(roots, &dirty_set) → for dirty_set elements: recalculate → for others: return as-is ``` --- ## Tests | Test | What it checks | |------|---------------| | `test_basic_dependency_tracking` | Two elements, two variables, correct dirty_set | | `test_scan_value` | Parse `$var` from a string | | `test_scan_no_vars` | String without `$` creates no dependencies | | `test_take_dirty_set` | `take_dirty_set()` clears the internal set | | `test_reset` | `reset()` clears everything |