Действия
Действия — это эффекты типа «выстрелил и забыл». Когда машина состояний выполняет переход, она может выполнять действия. Действия происходят в ответ на события и обычно определяются в переходах в свойстве actions: [...]. Действия также могут быть определены для любого перехода, который входит в состояние, в свойстве состояния entry: [...], или для любого перехода, который выходит из состояния, в свойстве состояния exit: [...].
Действия также могут быть в entry или exit состояния, как одиночное действие или как массив.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | |
Примеры действий:
- Логирование сообщения
- Отправка сообщения другому актору
- Обновление контекста
Действия входа и выхода¶
Действия входа — это действия, которые происходят при любом переходе, который входит в узел состояния. Действия выхода — это действия, которые происходят при любом переходе, который выходит из узла состояния.
Действия входа и выхода определяются с помощью атрибутов entry: [...] и exit: [...] на узле состояния. Вы можете запускать несколько действий входа и выхода в состоянии. Финальные состояния верхнего уровня не могут иметь действий выхода, поскольку машина останавливается и дальнейшие переходы невозможны.
Информация
Порядок выполнения действий для перехода:
- Действия выхода — все действия выхода покидаемых узлов состояний, от атомарного узла состояния вверх
- Действия перехода — все действия, определённые на выбранном переходе
- Действия входа — все действия входа входимых узлов состояний, от родительского состояния вниз
Это следует алгоритму SCXML для выполнения микрошага.
Объекты действий¶
Объекты действий имеют type действия и необязательный объект params:
- Свойство
typeдействия описывает действие. Действия с одинаковым типом имеют одинаковую реализацию. - Свойство
paramsдействия содержит параметризованные значения, относящиеся к действию.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
Динамические параметры действий¶
Вы можете динамически передавать параметры в свойстве params объектам действий, используя функцию, которая возвращает параметры. Функция принимает объект, содержащий текущий context и event в качестве аргументов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Это рекомендуемый подход для того, чтобы сделать действия более переиспользуемыми, поскольку вы можете определять действия, которые не зависят от типов context или event машины.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
Встроенные действия¶
Вы можете объявлять действия как встроенные функции:
1 2 3 4 5 6 7 8 9 10 | |
Встроенные действия полезны для прототипирования и простых случаев, но мы обычно рекомендуем использовать объекты действий.
Реализация действий¶
Вы можете настроить реализации для именованных действий в свойстве actions функции setup(...):
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Вы также можете предоставить реализации действий для переопределения существующих действий в методе machine.provide(...), который создаёт новую машину с той же конфигурацией, но с предоставленными реализациями:
1 2 3 4 5 6 7 8 9 10 11 | |
Встроенные действия XState¶
XState предоставляет ряд полезных встроенных действий, которые являются основной частью логики ваших машин состояний, а не просто побочными эффектами.
Внимание
Встроенные действия, такие как assign(…), sendTo(…) и raise(…), не императивны; они возвращают специальный объект действия (например, { type: 'xstate.assign', … }), который интерпретируется машиной состояний. Не вызывайте встроенные действия в пользовательских функциях действий.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | |
Действие assign¶
Действие assign(...) — это специальное действие, которое присваивает данные контексту состояния. Аргумент assignments в assign(assignments) указывает, какие присвоения контексту должны быть выполнены.
Присвоения могут быть объектом пар ключ-значение, где ключи — это ключи context, а значения — либо статические значения, либо выражения, возвращающие новое значение:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | |
Для более динамических присвоений аргумент, переданный в assign(...), также может быть функцией, которая возвращает частичное или полное значение context:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Внимание
Не мутируйте объект context. Вместо этого вы должны использовать действие assign(...) для иммутабельного обновления context. Если вы мутируете объект context, вы можете получить неожиданное поведение, такое как мутация context других акторов.
Действие raise¶
Действие raise — это специальное действие, которое поднимает событие, получаемое той же машиной. Поднятие события — это способ, которым машина может «отправить» событие самой себе:
1 2 3 4 5 6 | |
Внутренне, когда событие поднимается, оно помещается во «внутреннюю очередь событий». После завершения текущего перехода эти события обрабатываются в порядке вставки (первым пришёл — первым вышел, или FIFO). Внешние события обрабатываются только после обработки всех событий во внутренней очереди событий.
Поднятые события могут быть динамическими:
1 2 3 4 5 6 7 8 9 | |
События также могут быть подняты с задержкой, что не поместит их во внутреннюю очередь событий, поскольку они не будут обработаны немедленно:
1 2 3 4 5 6 | |
Действие sendTo¶
Действие sendTo(...) — это специальное действие, которое отправляет событие определённому актору.
1 2 3 4 5 6 7 8 9 | |
Событие может быть динамическим:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Целевой актор может быть ID актора или самой ссылкой на актора:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Другие опции, такие как delay и id, могут быть переданы как 3-й аргумент:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Отложенные действия могут быть отменены по их id. См. cancel(...).
Действие sendParent¶
Действие sendParent(...) — это специальное действие, которое отправляет событие родительскому актору, если он существует.
Совет
Рекомендуется использовать sendTo(...), передавая ссылки на акторов (например, ссылку на родительского актора) другим акторам через input или события и сохраняя эти ссылки на акторов в context, а не использовать sendParent(...). Это избегает тесной связи между акторами и может быть более типобезопасным.
Пример с использованием input:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | |
Пример с использованием input (TypeScript):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | |
Действие enqueueActions¶
Создатель действия enqueueActions(...) — это действие высшего уровня, которое ставит в очередь действия для последовательного выполнения, фактически не выполняя ни одно из действий. Оно принимает функцию обратного вызова, которая получает context, event, а также функции enqueue и check:
-
Функция
enqueue(...)используется для постановки действия в очередь. Она принимает объект действия или функцию действия:1 2 3 4 5 6 7 8 9 10 11 12 13
actions: enqueueActions(({ enqueue }) => { // Поставить в очередь объект действия enqueue({ type: 'greet', params: { message: 'hi' }, }); // Поставить в очередь функцию действия enqueue(() => console.log('Hello')); // Поставить в очередь простое действие без параметров enqueue('doSomething'); }); -
Функция
check(...)используется для условной постановки действия в очередь. Она принимает объект условия или функцию условия и возвращает булево значение, представляющее, вычисляется ли условие какtrue:1 2 3 4 5
actions: enqueueActions(({ enqueue, check }) => { if (check({ type: 'everythingLooksGood' })) { enqueue('doSomething'); } }); -
Также есть вспомогательные методы на
enqueueдля постановки встроенных действий в очередь:enqueue.assign(...): Ставит в очередь действиеassign(...)enqueue.sendTo(...): Ставит в очередь действиеsendTo(...)enqueue.raise(...): Ставит в очередь действиеraise(...)enqueue.spawnChild(...): Ставит в очередь действиеspawnChild(...)enqueue.stopChild(...): Ставит в очередь действиеstopChild(...)enqueue.cancel(...): Ставит в очередь действиеcancel(...)
Поставленные в очередь действия могут вызываться условно, но они не могут быть поставлены в очередь асинхронно.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | |
Вы можете использовать параметры с ссылочными действиями enqueue:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Действие log¶
Действие log(...) — это простой способ логирования сообщений в консоль.
1 2 3 4 5 6 7 8 9 | |
Действие cancel¶
Действие cancel(...) отменяет отложенное действие sendTo(...) или raise(...) по их ID:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Действие stopChild¶
Действие stopChild(...) останавливает дочернего актора. Акторы могут быть остановлены только их родительским актором:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Моделирование¶
Если вам нужно только выполнять действия в ответ на события, вы можете создать самопереход, который имеет только определённый actions: [ ... ]. Например, машина, которой нужно только присваивать значения в context в переходах, может выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
Сокращения¶
Для простых действий вы можете указать строку действия вместо объекта действия. Хотя мы предпочитаем использовать объекты для согласованности.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Действия и TypeScript¶
TypeScript
XState v5 требует TypeScript версии 5.0 или выше.
Для лучших результатов используйте последнюю версию TypeScript. Подробнее о XState и TypeScript
Чтобы строго настроить типы действий, используйте функцию setup({ ... }) и поместите реализации действий в объект actions: { ... }. Ключ — это тип действия, а значение — реализация функции действия.
Вы также должны строго типизировать параметры функции действия, которые передаются как второй аргумент функции действия.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Если вы не используете setup({ ... }) (настоятельно рекомендуется), вы можете строго типизировать actions вашей машины в свойстве types.actions конфигурации машины.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
Шпаргалка по действиям¶
Шпаргалка: действия входа и выхода¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Шпаргалка: действия перехода¶
1 2 3 4 5 6 7 8 9 10 11 12 | |
Шпаргалка: встроенные функции действий¶
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Шпаргалка: настройка действий¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | |
Шпаргалка: предоставление действий¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Шпаргалка: действие assign¶
С присваивателями свойств¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
С функциями-присваивателями¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Шпаргалка: действие raise¶
1 2 3 4 5 6 7 8 9 | |
Шпаргалка: действие sendTo¶
1 2 3 4 5 6 7 8 9 | |
Шпаргалка: действие enqueueActions¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |