3.8 KiB
3.8 KiB
Модуль реактивности: src/interpreter/reactive.rs
Система отслеживания зависимостей между переменными и элементами VDOM. Позволяет пересчитывать только изменившиеся элементы (Phase 3).
ElementId(u32)
Уникальный идентификатор элемента в VDOM-дереве. Раздаётся ReactiveTracker::alloc_id()
во время загрузки шаблона.
#[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
Граф зависимостей: переменная → список элементов, которые её используют.
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 паттернов:
"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() очищает всё |