Files
Glint-Runtime/docs/en/modules/03-reactive.md

93 lines
2.7 KiB
Markdown

# 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<ElementId>`
- Key in `dependencies: HashMap<ElementId, HashSet<String>>`
- 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<String, HashSet<ElementId>>,
dependencies: HashMap<ElementId, HashSet<String>>,
dirty_set: HashSet<ElementId>,
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<ElementId>` | 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 |