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

93 lines
3.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Модуль реактивности: `src/interpreter/reactive.rs`
Система отслеживания зависимостей между переменными и элементами VDOM.
Позволяет пересчитывать только изменившиеся элементы (Phase 3).
---
## `ElementId(u32)`
Уникальный идентификатор элемента в VDOM-дереве. Раздаётся `ReactiveTracker::alloc_id()`
во время загрузки шаблона.
```rust
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct ElementId(pub u32);
```
**Используется как:**
- Ключ в `dirty_set: HashSet<ElementId>`
- Ключ в `dependencies: HashMap<ElementId, HashSet<String>>`
- Поле в `Element::element_id` (связь VDOM → tracker)
- Источник для `iced::widget::Id` (Phase 9.2: `format!("ti:{}", id.0)`)
- Источник для scrollable_id (`el.element_id.0 as u64`)
---
## `ReactiveTracker`
Граф зависимостей: переменная → список элементов, которые её используют.
```rust
pub struct ReactiveTracker {
subscribers: HashMap<String, HashSet<ElementId>>,
dependencies: HashMap<ElementId, HashSet<String>>,
dirty_set: HashSet<ElementId>,
next_id: u32,
}
```
**Поля:**
- `subscribers` — для каждой переменной: какие ElementId от неё зависят
- `dependencies` — для каждого элемента: от каких переменных он зависит (обратная связь)
- `dirty_set` — элементы, которые нужно пересчитать в следующем фрейме
- `next_id` — счётчик для `alloc_id()`
### Методы
| Метод | Описание |
|-------|----------|
| `new()` | Пустой tracker |
| `alloc_id() -> ElementId` | Выделить новый ID, увеличить счётчик |
| `add_dependency(element, var_name)` | Зарегистрировать зависимость |
| `scan_value(element, value)` | Сканировать строку на `$var` и добавить зависимости |
| `on_variable_changed(name)` | Пометить все зависимые элементы как dirty |
| `take_dirty_set() -> HashSet<ElementId>` | Забрать dirty_set и очистить |
| `is_dirty(id) -> bool` | Проверить, помечен ли элемент |
| `reset()` | Очистить все данные |
### scan_value()
Парсит строку в поиске `$var_name` паттернов:
```rust
"Hello $name, you are $age years old"
// → add_dependency(element, "name")
// → add_dependency(element, "age")
```
Используется во время загрузки шаблона для каждой properties строки,
содержащей `$`. В результате каждый элемент знает, от каких переменных зависит.
### Цикл обновления
```
Событие → update() → on_variable_changed("var")
→ dirty_set = {element_A, element_B, ...}
→ take_dirty_set() → evaluate_vdom_incr(roots, &dirty_set)
→ для элементов в dirty_set: пересчитать
→ для остальных: вернуть как есть
```
---
## Тесты
| Тест | Что проверяет |
|------|--------------|
| `test_basic_dependency_tracking` | Два элемента, две переменные, правильность dirty_set |
| `test_scan_value` | Парсинг `$var` из строки |
| `test_scan_no_vars` | Строка без `$` не создаёт зависимостей |
| `test_take_dirty_set` | `take_dirty_set()` очищает внутренний set |
| `test_reset` | `reset()` очищает всё |