Перейти к основному содержимому

Event

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

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

Структура

  • Методы

    • map: создает производное событие на основе данных из исходного
    • prepend: создает событие-триггер для преобразования данных перед запуском исходного эвента
    • filterMap: создает производное событие на основе данных из исходного с возможностью отмены вызова
    • watch: вызывает функцию с сайд-эффектами при каждом срабатывании события
  • Свойства

    • shortName: имя события
    • sid: стабильный идентификатор события

Примеры

Методы

map

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

Формула

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

Возвращает

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

Примеры

Пример использования map
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

Создаёт событие-триггер для преобразования данных перед запуском исходного эвента. По сравнению с 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

Возвращает

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

Примеры

Пример использования prepend
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

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

note

Метод добавлен в 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

note

Если требуется только фильтрация вызовов без трансформации данных, то оптимальнее использовать 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"])

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

Использование nullable react ref с filterMap
note

Методы 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>
</>
)
}

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

watch

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

note

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

Формула

declare const event: Event<T>

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

Аргументы

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

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

Возвращает

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

Примеры

Пример использования watch
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

Дополнительные методы

filter

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

note

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

Формула

declare const eventA: Event<T>

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

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

Аргументы

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

Возвращает

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

note

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

Примеры

Пример использования filter
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

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