Реакции
Реакция — это правило модели. Она не хранит состояние, не сообщает о факте и не выполняет внешнюю работу. Ее задача — связать эти части: событие произошло, стор изменился, эффект завершился, значит модель должна выполнить правило.
Чаще всего реакция живет рядом с теми юнитами, которые связывает. Так по модели видно не только “какие данные есть”, но и “почему они меняются”.
const queryChanged = event<string>();
const searchSubmitted = event<void>();
const query = store("");
const results = store({ items: [] as string[] });
const searchFx = effect(async (text: string) => {
const response = await fetch(`/api/search?q=${encodeURIComponent(text)}`);
return (await response.json()) as string[];
});
reaction({
on: queryChanged,
run(text) {
query.value = text;
},
});
reaction({
on: searchSubmitted,
run() {
void searchFx(query.value);
},
});
reaction({
on: searchFx.doneData,
run(items) {
results.items = items;
},
});Здесь события остаются маленькими: они только называют произошедшее. Эффект занимается запросом. Сторы помнят состояние. Реакции описывают причинность между ними.
Автоматические зависимости
По умолчанию удобно начинать с реакции без on. Внутри такой реакции вы читаете сторы, а Virentia запоминает, от каких сторов зависит правило. Когда один из прочитанных сторов меняется, реакция запускается снова в том же scope.
const query = store("");
const online = store(true);
const canSearch = store(false);
reaction(() => {
canSearch.value = online.value && query.value.trim().length > 2;
});Этот режим особенно полезен, когда зависимости проще выразить чтением состояния, а не списком источников. Если внутри есть ветвление, список зависимостей обновляется после каждого запуска: реакция будет слушать именно те сторы, которые были прочитаны в актуальной ветке.
Если значение полностью выводится из других сторов и не требует записи в отдельный стор, сначала посмотрите на computed. Реакция нужна, когда правило должно выполнить действие: записать состояние, вызвать эффект, отправить событие или синхронизироваться с внешним кодом.
Явный on
on нужен, когда важна причина запуска: конкретное событие, эффект или юнит жизненного цикла эффекта. В этом режиме реакция не запускается при создании. Она срабатывает только от указанного юнита и получает его payload.
reaction({
on: messageReceived,
run(message) {
messages.items = [...messages.items, message];
},
});Используйте явный on, когда payload является частью правила. Например, “пришло сообщение”, “форма отправлена”, “запрос успешно завершился”, “эффект был отменен”. Это читается лучше, чем реакция, которая просто наблюдает за состоянием и пытается угадать, что произошло.
Можно слушать несколько источников, если правило для них действительно одинаковое:
reaction({
on: [saved, cancelled],
run() {
modalOpened.value = false;
},
});Остановка
Реакция возвращает объект со stop(). После остановки она отвязывается от зависимостей и больше не получает новые запуски.
const subscription = reaction({
on: ticked,
run() {
count.value += 1;
},
});
subscription.stop();В динамических моделях чаще не нужно вызывать stop() вручную. Создавайте такие реакции внутри owner: при dispose Virentia отвяжет их вместе с остальной временной работой.