Scope и жизненный цикл компонента
Сам модуль загружается один раз, но отдельный компонент внутри него может включаться и выключаться много раз. Если при каждом включении создавать новый таймер или подписку и не отменять предыдущую, один обработчик постепенно превратится в несколько. По той же причине на экране могут оставаться старые визуальные объекты.
Scope — небольшой контейнер для всего, чем владеет один активный компонент.
Создайте его при включении, зарегистрируйте ресурсы и вызовите dispose() при
выключении.
Минимальный пример
Заголовок раздела «Минимальный пример»import { scheduler, scope } from "@killscript/sdk/client";
const active = scope();
active.using(scheduler.every(0.25, () => { // Обновите HUD из текущего состояния игры.}));active.defer(() => print("HUD выключен"));
// Позже, когда компонент выключается:active.dispose();using() принимает EventSubscription, например результат планировщика или
наблюдателя за событием. defer() сохраняет обычную функцию очистки для
состояния, которое SDK не может сбросить автоматически.
| Метод | Что хранит или делает |
|---|---|
using() | Подписку или задачу с Cancel() |
defer() | Функцию очистки, заданную вашим кодом |
world() | Клиентский объект, созданный через WorldVisuals |
dispose() | Освобождает все сохранённые ресурсы |
isDisposed() | Показывает, был ли scope уже очищен |
Включаемый и выключаемый компонент
Заголовок раздела «Включаемый и выключаемый компонент»Храните текущий scope рядом с состоянием компонента. Каждое включение получает новый экземпляр, а каждое выключение очищает именно его:
import { type ClientScope, scheduler, scope, visuals,} from "@killscript/sdk/client";
let active: ClientScope | undefined;
export function enableMarker(getPosition: () => Vector3 | undefined): void { if (active !== undefined) return;
const position = getPosition(); if (position === undefined) return;
const next = scope(); const marker = next.world(visuals.overlay({ position: position, size: new Vector3(0.8, 0.02, 0.8), color: new Color(0, 1, 1, 0.55), })); if (marker === undefined) { next.dispose(); return; }
next.using(scheduler.every(0.25, () => { const current = getPosition(); if (current !== undefined) marker.SetPosition(current); })); active = next;}
export function disableMarker(): void { active?.dispose(); active = undefined;}У клиентского scope есть world(). Метод возвращает тот же объект, но
запоминает, что его нужно удалить через WorldVisuals при очистке. Это удобно,
когда визуальный объект должен существовать ровно столько же, сколько компонент.
Что делает dispose
Заголовок раздела «Что делает dispose»При первом вызове dispose() scope:
- отменяет подписки в обратном порядке;
- удаляет клиентские объекты мира в обратном порядке;
- запускает функции из
defer()в обратном порядке.
Повторный вызов безопасен и ничего не делает. Если добавить подписку, объект или обработчик в уже закрытый scope, ресурс очистится сразу. Благодаря этому поздний результат другой операции не оставит после себя утечку.
В Reflex доступен такой же scope() с using() и defer(), но без world():
WorldVisuals существует только на клиенте.
Смотрите также Планировщик и Мировые визуальные объекты.