События
Хотя в effector есть три основные концепции — события, сторы и эффекты, но именно события можно назвать основой для работы вашего приложения. Весь frontend построен поверх событийной модели, вы наверняка уже сталкивались с событиями при работе в JavaScript, например addEventListener или в React с onClick и другими обработчиками – это все события, на которые мы можем подписаться, так и в effector мы можем создать свое событие с помощью createEvent и подписаться на его вызов:
let counter = 10;
document.addEventListener("click", () => { counter = 13;});import { createEvent, createStore, sample } from "effector";
const $counter = createStore(10);
const click = createEvent();
sample({ clock: click, fn: () => 13, target: $counter,});События в effector не то же самое, что события DOM, данный пример служит демонстрацией похожей концепции работы.
Зачем нужны события
Весь код на effector строится поверх событий, например если вы передадите стор в параметр clock у метода sample, то такой sample будет вызываться при срабатывании события updates у переданного стора:
// этот код эквивалентенimport { createStore, sample } from "effector";
const $someStore = createStore();sample({ clock: $someStore, // ...});// этот код эквивалентенimport { createStore, sample } from "effector";
const $someStore = createStore();sample({ clock: $someStore.updates, // ...});Событие само по себе просто означает факт какого-то действия, клик по кнопке, обновление данных, показ уведомления, и прочее. Все что они делают это передают информацию и сообщают их подписчикам, что его вызвали.
Для более простого понимания – событиями является все, с чем пользователь может взаимодействовать, а также внутренняя работы вашей логики. То есть помимо UI ориентированных событий по типу buttonClicked, inputChanged и прочее, у вас также могут быть и события завязанные на обновлении данных: valueUpdated или errorOccured.
Например у эффектов имеются встроенные событие done, которое срабатывает при успешном завершении работы эффекта, а также событие fail, если во время выполнения выбросилась ошибка. А сторы имеют событие updates, которое вызывается при его обновлении.
События также позволяют нам держать код слабо связным, что упрощает поддержку и тестирование.
На странице Как мыслить в парадигме effector мы подробно рассказываем о том, почему события важны, чем они еще полезны и какую пользу могут принести.
Как использовать события
Создать события мы можем с помощью метода createEvent, а далее подписываться на вызов этого события с помощью метода sample:
import { sample, createEvent } from "effector";
const event = createEvent();
sample({ clock: event, // ...});Если вы не знакомы с методом sample, то в примере с событиями он создает подписку на переданное событие в clock, а когда событие вызывается запускает цепочку выполнения. Более подробно вы познакомиться с логикой его работы на странице Композиция юнитов.
С помощью событий мы можем как обновлять сторы, так и вызывать эффекты или другие события:
import { sample, createStore, createEvent } from "effector";
const $clicksCount = createStore(0);
const userClicked = createEvent<void>();
// обновляем стор счетчикsample({ clock: userClicked, source: $clicksCount, fn: (clicksCount) => count + 1, target: $clicksCount,});
userClicked();import { createEvent, createEffect, sample } from "effector";
const startFetch = createEvent<string>();const fetchFx = createEffect((url: string) => { // ...});
// вызываем эффектsample({ clock: startFetch, target: fetchFx,});
startFetch("/fake-api/users");Важная особенность событий, что они могут принимать только один аргумент, остальные будут проигнорированы. Если вам необходимо передать несколько аргументов, то используйте объект:
const event = createEvent<{ a: number; b: string }>();
event({ a: 1, b: "string",});Вызов события
Вызвать событие можно двумя путями: императивно и декларативно.
Императивным способ вызова это наиболее привычный, когда мы вызываем событие как функцию event(), такой способ, скорее всего, вы будете использовать при вызове события в UI, когда передаете в onClick, onChange обработчики и другие:
import { createEvent } from "effector";// можно использовать любой другой фреймворк и пакет с его интеграциейimport { useUnit } from "effector-react";
const clickHappened = createEvent<void>();
// view.tsximport { useUnit } from "effector-react";
const Component = () => { const click = useUnit(clickHappened);
return ( <div> <button onClick={() => click()}>click</button> </div> );};Заметьте, чтобы вызвать событие в UI при работе с фреймворком, вам нужно использовать хук useUnit.
Декларативный вызов это, например, когда мы подписываемся событием на другое событие с помощью метода sample и аргумента target. Событие переданное в target вызовется при срабатывании clock:
import { createEvent, sample } from "effector";
const firstTriggered = createEvent<void>();const secondTriggered = createEvent<void>();
sample({ clock: firstTriggered, target: secondTriggered,});Декларативыный способ вызова события это единственный правильный способ при работе с sample. Однако вы можете вызывать императивно с помощью метода createAction или в теле эффекта.
Связанные API и статьи
- API
Event API— Описание событий, их методов и свойствcreateEvent— Создание нового событияsample— Ключевой оператор для построения связей между юнитамиStore API— Описание сторов, его методов и свойств
- Статьи
Документация на английском языке - самая актуальная, поскольку её пишет и обновляет команда effector. Перевод документации на другие языки осуществляется сообществом по мере наличия сил и желания.
Помните, что переведенные статьи могут быть неактуальными, поэтому для получения наиболее точной и актуальной информации рекомендуем использовать оригинальную англоязычную версию документации.