Определите наблюдаемое время жизни
hooks.mounted вызывается после монтирования. hooks.unmounted — при завершении соответствующего времени жизни. Каждый хук может быть функцией, событием или эффектом; вызов привязан к области. Оба получают итоговые свойства, сохранённые для этого времени жизни.
import {createElement as h} from "@fiberfx/hyperscript";
import {event, store} from "@fiberfx/hypergraph";
import {reflect} from "@fiberfx/reflect";
const changed = event<string>();
const recorded = event<string>();
export const $name = store("Ada").on(changed, (_, name) => name);
export const $history = store<string[]>([])
.on(recorded, (history, entry) => [...history, entry]);
export const Lifetime = reflect({
view: (p: {name: string}) => h("p", null, p.name),
bind: {name: $name},
hooks: {
mounted: props => recorded(`mounted: ${props.name}`),
unmounted: props => recorded(`unmounted: ${props.name}`),
},
});
Владелец решает, выводить ли Lifetime, например через visible ? h(Lifetime, {}) : null. Историю $history читайте в отдельном представлении через общий слой привязки. Оба представления должны находиться под нужным Provider.
Обычное обновление свойства не начинает новое время жизни хуков. Замена области завершает прежнее и начинает следующее. Перестановка строки с прежним ключом его не завершает. Хуки variant принадлежат обёртке, поэтому сама смена ветви их не перезапускает.
Смонтируйте, обновите и удалите
Откройте эксперимент со временем жизни. Оставьте имя Ada и нажмите Смонтировать. Не скрывая представление, замените имя на Grace. Затем нажмите Размонтировать.
До удаления предскажите два значения: текст представления и имя в истории хуков. Они отвечают на разные вопросы: что отображается сейчас и какие свойства были сохранены в начале этого времени жизни.
Сравните текущее и сохранённое
Смонтированное представление должно обновиться до Grace. В истории должны появиться монтирование: Ada, затем размонтирование: Ada. Обновление свойства не должно добавлять ещё одну запись монтирования.
Снова смонтируйте представление, пока в поле Grace. Новое время жизни должно сохранить Grace. История позволяет проследить порядок событий, но не доказывает автоматическое освобождение всех ресурсов приложения. В настоящем тесте фиксируйте и проверяйте конкретный ресурс, которым владеете.
Откажитесь от неверного ожидания
Ожидание «unmounted получает последнее отображённое имя» неверно для этих хуков. Нельзя освобождать ресурс по новому имени, если он был создан с другим сохранённым ключом. Свяжите создание и освобождение с одной идентичностью времени жизни. Реакции на изменение значения разместите в модели или в компонентном хуке с соответствующей зависимостью.
Возвращённая из hooks.mounted функция очистки не относится к API Reflect: возвращаемое значение игнорируется. Если подходит этот контракт, используйте отдельный unmounted. Дескрипторов ресурсов, автоматического учёта функций освобождения и нового языка жизненного цикла в 4.1.1 нет.
Начните новое наблюдение
Нажмите Начать упражнение заново и повторите Ada → монтирование → Grace → размонтирование. Перезапуск удаляет сцену вместе со сбросом значений модели; само удаление может добавить запись очистки. Читайте итоговую историю, а не предполагайте, что сброс означает отсутствие очистки.
В тесте сначала размонтируйте компонент, проверьте очистку и лишь затем удалите историю или освободите область. Обратный порядок может скрыть результат очистки или заставить её обращаться к уже освобождённой области.
Проверьте серверную границу
При серверном рендеринге читаются значения области, но не вызываются ни mounted, ни unmounted. Выведите то же представление с двумя областями запросов и разными именами, сравните HTML и проверьте, что история хуков пуста. Это отдельные проверки изоляции вывода и отсутствия хуков.
Не запускайте браузерную работу из проекции: проекции участвуют и в серверном рендеринге. Владение браузерным ресурсом задавайте на клиентской границе времени жизни, а создание и освобождение области запроса оставьте серверу. Последняя глава превращает наблюдаемые контракты в регрессионные проверки.