Event (событие, эвент) это декларация намерения сделать что-либо: запустить вычисления, отправить сообщение другой секции приложения или обновить состояния в приложении. Одна из основных управляющих сущностей, при срабатывании запускает цепочки реактивных вычислений в приложении. Является юнитом

События можно вызывать как обычные функции (императивный вызов) а также подключать в различные методы api включая sample, guard и split (декларативное подключение). При императивном вызове принимают максимум один аргумент и всегда возвращают переданные данные

Методы

map(fn)

Создает производное событие на основе данных из исходного

Формула

declare const eventA: Event<T>

const eventB = eventA.map(/*fn*/(data: T) => S)
-> Event<S>

При вызове исходного события eventA, функция-обработчик fn будет вызвана с поступившими данными, после чего производный эвент eventB будет вызван с результатом вычислений


    eventA -> fn -> eventB

Аргументы

  1. fn: (data: T) => S

    Функция-обработчик, которая будет вычислять данные для передачи в производное событие eventB на основе данных из исходного эвента eventA. Должна быть чистой

    Аргументы

    • data: Данные с которыми сработало исходное событие eventA

    Возвращает

    Данные для передачи в производное событие eventB

Возвращает

Новое, производное событие

Пример

import { createEvent } from "effector";

const updateUser = createEvent();
const userNameUpdated = updateUser.map(({ name }) => name);
const userRoleUpdated = updateUser.map(({ role }) => role.toUpperCase());

userNameUpdated.watch((name) => console.log(`Имя пользователя изменено на ${name}`));
userRoleUpdated.watch((role) => console.log(`Роль пользователя изменена на ${role}`));

updateUser({ name: "john", role: "admin" });
// => Имя пользователя изменено на john
// => Роль пользователя изменена на ADMIN

Запустить пример

prepend(fn)

Создаёт событие-триггер для преобразования данных перед запуском исходного эвента. По сравнению с map, работает в обратном направлении

Формула

declare const targetEvent: Event<S>

const trigger = targetEvent.prepend(/*fn*/(data: T) => S)
-> Event<T>

При вызове события trigger, функция-обработчик fn будет вызвана с поступившими данными, после чего эвент targetEvent будет вызван с результатом вычислений


    trigger -> fn -> targetEvent

Аргументы

  1. fn: (data: T) => S

    Функция-обработчик, которая будет вычислять данные для передачи в исходное событие targetEvent на основе данных эвента trigger. Должна быть чистой

    Аргументы

    • data: Данные с которыми сработало событие trigger

    Возвращает

    Данные для передачи в исходное событие targetEvent

Возвращает

Новое событие

Пример

Пример использования
import { createEvent } from "effector";

const userPropertyChanged = createEvent();

userPropertyChanged.watch(({ field, value }) => {
  console.log(`Свойство пользователя "${field}" изменено на ${value}`);
});

const changeName = userPropertyChanged.prepend((name) => ({
  field: "name",
  value: name,
}));
const changeRole = userPropertyChanged.prepend((role) => ({
  field: "role",
  value: role.toUpperCase(),
}));

changeName("john");
// => Свойство пользователя "name" изменено на john

changeRole("admin");
// => Свойство пользователя "role" изменено на ADMIN

changeName("alice");
// => Свойство пользователя "name" изменено на alice

Запустить пример

filterMap(fn)

Создает производное событие на основе данных из исходного с возможностью отмены вызова

info

Метод добавлен в effector 20.0.0

Формула

declare const eventA: Event<T>

const eventB = eventA.filterMap(
  /*fn*/ (data: T) => S | void
)
-> Event<S>

При вызове исходного события eventA, функция-обработчик fn будет вызвана с поступившими данными, после чего, если функция вернула не undefined, производный эвент eventB будет вызван с результатом вычислений


    eventA -> fn -> eventB

info

Если требуется только фильтрация вызовов без трансформации данных, то оптимальнее использовать guard

Аргументы

  1. fn: (data: T) => S | void

    Функция-обработчик, которая будет вычислять данные для передачи в производное событие eventB на основе данных из исходного эвента eventA. Должна быть чистой

    Аргументы

    • data: Данные с которыми сработало исходное событие eventA

    Возвращает

    Данные для передачи в производное событие eventB либо undefined, если вызов eventB не требуется

Возвращает

Новое, производное событие

Пример

Использование с методами JavaScript возвращающими undefined

const listReceived = createEvent<string[]>()
const effectorFound = listReceived.filterMap(list => list.find(name => name === 'effector'))

effectorFound.watch(name => console.info("found", name))
listReceived(["redux", "effector", "mobx"]) // found effector
listReceived(["redux", "mobx"])

Запустить пример

Использование c nullable React ref

info

Методы modal.showModal и modal.close – стандартные возможности dom-элемента <dialog>

Статья в MDN про showModal

import React from "react";
import { createEvent, createStore } from "effector";

const openModal = createEvent();
const closeModal = createEvent();

const openModalUnboxed = openModal.filterMap((ref) => {
  if (ref.current) return ref.current;
});
const closeModalUnboxed = closeModal.filterMap((ref) => {
  if (ref.current) return ref.current;
});

openModalUnboxed.watch((modal) => modal.showModal());
closeModalUnboxed.watch((modal) => modal.close());

const App = () => {
  const modalRef = React.useRef(null);
  return (
    <>
      <dialog ref={modalRef}>
        <form method="dialog">
          <fieldset>
            <legend>Модальное окно</legend>
            Нажмите для закрытия
            <button onSubmit={() => closeModal(modalRef)} type="submit"></button>
          </fieldset>
        </form>
      </dialog>

      <button onClick={() => openModal(modalRef)}>Открыть модальное окно</button>
    </>
  );
};

Запустить пример

filter({fn})

Создает производное событие с возможностью отмены вызова

tip

Более гибким способом фильтрации является sample, рекомендуется использовать именно его.

Формула

declare const eventA: Event<T>

const eventB = eventA.filter(/*config*/ {fn: (data: T) => boolean})
-> Event<T>

При вызове исходного события eventA, функция-обработчик fn будет вызвана с поступившими данными, после чего, если функция вернула истинное значение, производный эвент eventB будет вызван с теми же данными

Аргументы

  1. config: Объект конфигурации

Возвращает

Новое, производное событие

info

Объектная форма аргумента используется потому что event.filter(fn) был сокращённой формой filterMap

Пример

import { createEvent, createStore } from "effector";

const numbers = createEvent();

const positiveNumbers = numbers.filter({
  fn: ({ x }) => x > 0,
});

const $lastPositive = createStore(0).on(positiveNumbers, (n, { x }) => x);

$lastPositive.watch((x) => {
  console.log("последнее положительное значение:", x);
});

// => последнее положительное значение: 0

numbers({ x: 0 });
// ничего не произошло

numbers({ x: -10 });
// ничего не произошло

numbers({ x: 10 });
// => последнее положительное значение: 10

Запустить пример

watch(watcher)

Вызывает функцию с сайд-эффектами при каждом срабатывании события

info

По мере усложнения логики проекта оптимальнее заменить на комбинацию эффекта и sample

Формула

declare const event: Event<T>

event.watch(/*watcher*/ (data: T) => any)
-> Subscription

Аргументы

  1. watcher: (data: T) => any

    Функция с сайд-эффектами, в качестве первого аргумента получает значение с которым было вызвано событие. Возвращаемое значение не используется

Возвращает

Subscription: Функция отмены подписки, после её вызова watcher перестаёт получать обновления и удаляется из памяти. Повторные вызовы функции отмены подписки не делают ничего

Пример

import { createEvent } from "effector";

const sayHi = createEvent();
const stop = sayHi.watch((name) => {
  console.log(`Привет, ${name}!`);
});

sayHi("Боб");
// => Привет, Боб!

stop();

sayHi("Алиса");
// => ничего не произошло

Запустить пример

Свойства

shortName

Имя события. Задаётся либо явно, через поле name в createEvent, либо автоматически через Babel plugin. Используется для обработки сущностей программно, например при использовании хуков домена

Формула

declare const event: Event<any>

event.shortName
-> string

sid

Стабильный идентификатор события. Задаётся автоматически через Babel plugin

Формула

declare const event: Event<any>

event.sid
-> string | null
Перевод поддерживается сообществом

Документация на английском языке - самая актуальная, поскольку её пишет и обновляет команда effector. Перевод документации на другие языки осуществляется сообществом по мере наличия сил и желания.

Помните, что переведенные статьи могут быть неактуальными, поэтому для получения наиболее точной и актуальной информации рекомендуем использовать оригинальную англоязычную версию документации.

Соавторы