Миграция с XState v4 на v5
В приведенном ниже руководстве объясняется, как перейти с XState версии 4 на версию 5. Миграция с XState v4 на v5 должна быть простым процессом. Если вы застряли или у вас возникли вопросы, обратитесь к команде Stately в нашем Discord.
Примечание
Это руководство предназначено для разработчиков, которые хотят обновить свою кодовую базу с версии 4 до версии 5, а также будет полезно для всех разработчиков, желающих узнать различия между версией 4 и версии 5.
Примечание
Предпочитаете видео? Посмотрите наш вебинар по XState v5 на YouTube.
XState v5 и TypeScript¶
XState v5 и связанные с ним библиотеки написаны на TypeScript и используют сложные типы, чтобы обеспечить вам максимальную безопасность типов и логический вывод. XState v5 требует TypeScript версии 5.0 или более поздней. Для достижения наилучших результатов используйте последнюю версию TypeScript.
Следуйте этим рекомендациям, чтобы убедиться, что ваш проект TypeScript готов к использованию XState v5:
- Используйте последнюю версию TypeScript, версию 5.0 или более позднюю (обязательно).
1 | |
- Установите для параметра
strictNullChecksзначениеtrueв вашем файлеtsconfig.json. Это обеспечит правильную работу наших типов, а также поможет обнаружить ошибки в вашем коде (настоятельно рекомендуется).
1 2 3 4 5 6 7 8 9 | |
- Установите для параметра
skipLibCheckзначениеtrueв вашем файлеtsconfig.json(рекомендуется).
Создание машин и актеров¶
Используйте createMachine(), а не Machine()¶
Критическое изменение
Несовместимое изменение.
Функция Machine(config) теперь называется createMachine(config):
1 2 3 4 5 | |
1 2 3 4 5 6 | |
Используйте createActor(), а не interpret()¶
Критическое изменение
Несовместимое изменение.
Функция interpret() была переименована в createActor():
1 2 3 4 5 6 7 8 | |
1 2 3 4 5 6 7 8 | |
Используйте machine.provide(), а не machine.withConfig()¶
Критическое изменение
Несовместимое изменение.
Методmachine.withConfig() был переименован вmachine.provide():
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 | |
Установите контекст с помощью input, а не machine.withContext()¶
Критическое изменение
Несовместимое изменение.
Метод machine.withContext(...) больше нельзя использовать, поскольку context больше нельзя переопределить напрямую. Вместо этого используйте input:
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 | |
Действия упорядочены по умолчанию, predictableActionArguments больше не требуется¶
Критическое изменение
Несовместимое изменение.
По умолчанию действия теперь располагаются в предсказуемом порядке, поэтому флаг predictableActionArguments больше не требуется. Действия назначения всегда будут выполняться в том порядке, в котором они определены.
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 17 | |
Функция spawn() удалена.¶
Вместо использования импортированной функции spawn() для создания актеров внутри действий Assign(...):
- Используйте создатель действия
spawnChild(...)(предпочтительно) - Или используйте метод spawn(...)
из первого аргумента, переданного функции присваивания внутри действий assign(...)(полезно, если вам нужна ссылка на актера вcontext)
Прочтите документацию по порождению актеров для получения дополнительной информации.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
1 2 3 4 5 6 7 8 9 | |
Используйте getNextSnapshot(…) вместо machine.transition(…)¶
Метод machine.transition(…) теперь требует "области действия актера" для третьего аргумента, который создается внутри createActor(…). Вместо этого используйте getNextSnapshot(…), чтобы получить следующий снимок из некоторой логики актера на основе текущего снимка и события:
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 | |
Отправлять события явно вместо использования autoForward¶
Свойство autoForward в конфигурациях вызова было удалено. Вместо этого отправляйте события явно.
В общем, не рекомендуется пересылать все события актеру. Вместо этого пересылайте только те события, которые нужны актеру.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
1 2 3 4 5 6 7 8 9 | |
Штаты¶
Используйте state.getMeta() вместо state.meta¶
Критическое изменение
Несовместимое изменение.
Свойство state.meta было переименовано в state.getMeta():
1 2 | |
1 2 | |
Метод state.toStrings() был удален.¶
Критическое изменение
Несовместимое изменение.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Используйте state._nodes вместо state.configuration¶
Критическое изменение
Несовместимое изменение.
Свойство state.configuration было переименовано в state._nodes:
1 2 | |
1 2 | |
Чтение событий из API проверки вместо state.events¶
Свойство state.events было удалено, поскольку события не являются частью состояния, если вы явно не добавите их в context состояния. Вместо этого используйте inspection API для наблюдения за событиями или явно добавьте событие в context состояния:
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
1 2 3 4 5 6 7 8 | |
События и переходы¶
Функции реализации получают один аргумент¶
Критическое изменение
Несовместимое изменение.
Функции реализации теперь принимают один аргумент: объект с контекстом, событием и другими свойствами.
1 2 3 4 5 6 | |
1 2 3 4 5 6 | |
send() удален; используйте raise() или sendTo()¶
Критическое изменение
Несовместимое изменение.
Создатель действия send(...) удален. Вместо этого используйте raise(...) для отправки событий себе или sendTo(...) для отправки событий другим актерам.
Прочтите документацию по действию sendTo и действию raise для получения дополнительной информации.
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 10 11 | |
Совет перед переносом. Обновите проекты версии 4, чтобы использовать sendTo или Raise вместо send.
Используйте enqueueActions() вместо pure() и choose()¶
Методы pure() и choose() были удалены. Вместо этого используйте enqueueActions().
Для действий pure():
1 2 3 4 5 6 7 | |
1 2 3 4 5 6 | |
Для действий choose():
1 2 3 4 5 6 7 8 9 | |
1 2 3 4 5 6 7 8 9 | |
actor.send() больше не принимает строковые типы¶
Критическое изменение
Несовместимое изменение.
Строковые типы событий больше нельзя отправлять, например, actor.send(event); вместо этого вы должны отправить объект события:
1 2 | |
1 2 | |
Совет перед переносом: Обновите проекты версии 4, чтобы передать объект в .send().
state.can() больше не принимает строковые типы¶
Критическое изменение
Несовместимое изменение.
Строковые типы событий больше нельзя отправлять, например, в state.can(event); вместо этого вы должны отправить объект события:
1 2 | |
1 2 | |
Защищенные переходы используют guard, а не cond¶
Критическое изменение
Несовместимое изменение.
Свойство перехода cond для защищенных переходов теперь называется Guard:
1 2 3 4 5 6 7 8 9 | |
1 2 3 4 5 6 7 8 9 10 | |
Используйте params для передачи параметров действиям и охранникам¶
Критическое изменение
Несовместимое изменение.
Свойства, отличные от type для объектов действия и объектов защиты, должны быть вложены в свойство params; { type: 'someType', message: 'hello' } становится { type: 'someType', params: { message: 'hello' }}. Эти параметры затем передаются во второй аргумент реализации действия или защиты:
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 | |
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 | |
Совет перед переносом. Обновите объекты действий и защиты в проектах версии 4, чтобы переместить свойства (кроме типа) в объект 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 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Используйте явные бессобытийные («всегда») переходы¶
Критическое изменение
Несовместимое изменение.
Бессобытийные («всегда») переходы теперь должны определяться через свойство «всегда: { ... }» узла состояния; их больше нельзя определить с помощью пустой строки:
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Совет перед переносом. Обновите проекты версии 4, чтобы использовать параметр «всегда» для переходов eventless.
Используйте reenter: true, а не internal: false¶
Критическое изменение
Несовместимое изменение.
internal: false теперь reenter: true
Внешние переходы, ранее заданные с помощью «internal: false», теперь указываются с помощью «reenter: true»:
1 2 3 4 5 6 7 8 9 10 | |
1 2 3 4 5 6 7 8 9 10 | |
Переходы по умолчанию внутренние, а не внешние¶
Критическое изменение
Несовместимое изменение.
Все переходы являются внутренними по умолчанию. Это изменение актуально для переходов, определенных на узлах состояния с действиями «вход» или «выход», вызванными актерами или отложенными переходами («после»). Если вы полагались на предыдущее поведение XState v4, где переходы неявно повторно входили в узел состояния, используйте reenter: true:
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 | |
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 11 12 13 14 15 16 17 18 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Дочерние узлы состояния всегда вводятся повторно¶
Критическое изменение
Несовместимое изменение.
Дочерние узлы состояния всегда вводятся повторно, когда на них нацелены переходы (как внешние, так и внутренние), определенные на узлах составного состояния. Это изменение актуально только в том случае, если дочерний узел состояния имеет действия «входа» или «выхода», вызванных актеров или отложенных переходов («после»). Добавьте защиту stateIn, чтобы предотвратить нежелательный повторный вход в дочернее состояние:
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 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
Используйте stateIn() для проверки переходов состояний, а не in¶
Критическое изменение
Несовместимое изменение.
Свойство перехода in: 'someState' удалено. Вместо этого используйте guard:stateIn(...):
1 2 3 4 5 6 7 8 9 | |
1 2 3 4 5 6 7 8 9 | |
Используйте actor.subscribe() вместо state.history¶
Критическое изменение
Несовместимое изменение.
Свойство state.history удалено. Если вам нужен предыдущий снимок, вам следует сохранить его через actor.subscribe(...).
1 2 3 4 5 6 7 | |
1 2 3 4 | |
Совет перед переносом: Обновите проекты версии 4, чтобы отслеживать историю с помощью actor.subscribe().
Действия могут выбрасывать ошибки без escalate¶
Критическое изменение
Несовместимое изменение.
Создатель действия «эскалация» удален. В XState v5 действия могут вызывать ошибки, и они будут распространяться ожидаемым образом. Ошибки можно обрабатывать с помощью перехода onError.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
1 2 3 4 5 6 | |
Актеры¶
Используйте создатели логики актеров для invoke.src вместо функций¶
Критическое изменение
Несовместимое изменение.
Доступные создатели логики актеров:
createMachinefromPromisefromObservablefromEventObservablefromTransitionfromCallback
Дополнительную информацию см. в разделе Актеры.
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 | |
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 15 | |
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 10 | |
Используйте invoke.input вместо invoke.data¶
Критическое изменение
Несовместимое изменение.
Свойство invoke.data удалено. Если вы хотите предоставить контекст вызываемым актерам, используйте invoke.input:
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 | |
Используйте output в конечных состояниях вместо data¶
Критическое изменение
Несовместимое изменение.
Чтобы получить выходные данные от машины, которая достигла своего конечного состояния, используйте свойство верхнего уровня «output» вместо «data»:
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |
Чтобы обеспечить динамически генерируемый вывод, замените invoke.data на invoke.output и добавьте свойство output верхнего уровня:
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 | |
Не используйте преобразователи свойств во входных и выходных данных.¶
Критическое изменение
Несовместимое изменение.
Если вы хотите предоставить динамический контекст вызываемым актерам или создать динамический вывод из конечных состояний, используйте функцию вместо объекта с преобразователями свойств.
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 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
Используйте свойство actors для объекта options вместо services¶
Критическое изменение
Несовместимое изменение.
services были переименованы в actors:
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 | |
Для изменений используйте subscribe(), а не onTransition()¶
Критическое изменение
Несовместимое изменение.
Метод actor.onTransition(...) удален. Вместо этого используйте actor.subscribe(...).
1 2 3 4 5 | |
1 2 3 4 5 | |
createActor() (ранее interpret()) принимает второй аргумент для восстановления состояния¶
Критическое изменение
Несовместимое изменение.
interpret(machine).start(state) теперь называется createActor(machine, { snapshot }).start()
Чтобы восстановить актера в определенном состоянии, теперь вам следует передать это состояние как свойство snapshot аргумента options функции createActor(logic, options) . Свойство «actor.start()» больше не принимает аргумент «state».
1 2 3 | |
1 2 3 | |
Используйте actor.getSnapshot(), чтобы получить состояние актера¶
Критическое изменение
Несовместимое изменение.
Подписка на актера (actor.subscribe(...)) после запуска актера больше не будет немедленно создавать текущий снимок. Вместо этого прочитайте текущий снимок из actor.getSnapshot():
1 2 3 4 5 6 7 8 9 10 | |
1 2 3 4 5 6 7 | |
Перебор событий вместо использования actor.batch()¶
Критическое изменение
Несовместимое изменение.
Метод actor.batch([...]) для пакетной обработки событий удален.
1 2 3 4 | |
1 2 | |
Совет перед переносом. Обновите проекты версии 4, чтобы обеспечить циклическую обработку событий и отправку их в виде пакета.
Используйте snapshot.status === 'done' вместо snapshot.done¶
Критическое изменение
Несовместимое изменение.
Свойство snapshot.done, которое ранее было в объекте моментального снимка акторов конечного автомата, удалено. Вместо этого используйте snapshot.status === 'done', который доступен всем актерам:
1 2 3 4 5 6 7 8 9 | |
1 2 3 4 5 6 7 8 9 | |
state.nextEvents был удален¶
Критическое изменение
Несовместимое изменение.
Свойство state.nextEvents удалено, поскольку оно не является полностью безопасным/надежным способом определения следующих событий, которые могут быть отправлены актеру. Если вы хотите получить следующие события в соответствии с предыдущим поведением, вы можете использовать эту вспомогательную функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
Типскрипт¶
Используйте types вместо schema¶
Критическое изменение
Несовместимое изменение.
СвойствоmachineConfig.schema переименовано вmachineConfig.types:
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 10 11 | |
Используйте types.typegen вместо tsTypes¶
Критическое изменение
Несовместимое изменение.
Примечание
XState Typegen пока не полностью поддерживает XState v5. Тем не менее, машины со строгой типизацией все же можно создать и без Typegen.
Свойство «machineConfig.tsTypes» было переименовано и теперь находится в «machineConfig.types.typegen».
1 2 3 4 5 6 7 8 9 10 11 12 | |
1 2 3 4 5 6 7 8 9 10 11 12 | |
@xstate/реагировать¶
useInterpret() теперь называется useActorRef()¶
Критическое изменение
Несовместимое изменение.
Хук useInterpret(), который используется для возврата actorRef ("сервиса" в XState v4), переименован в useActorRef().
1 2 3 4 | |
1 2 3 4 | |
useActor(logic) теперь принимает логику актера, а не актера¶
Критическое изменение
Несовместимое изменение.
Хук useActor(logic) теперь принимает actor logic (например, fromPromise(...), createMachine(...) и т.д.) вместо существующего ActorRef.
Чтобы использовать существующий ActorRef, используйтеactor.send(...)для отправки событий и useSelector(actor, ...) для получения снимка:
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 | |
Используйте machine.provide() для предоставления реализаций в хуках¶
Критическое изменение
Несовместимое изменение.
Для динамического создания машин с предоставленными реализациями перехватчики useMachine(...), useActor(...) и useActorRef(...) больше не принимают:
- Ленивые создатели машин как первый аргумент
- Реализации, переданные во второй аргумент
Вместо этого machine.provide(...) следует передать непосредственно в первый аргумент.
Пакет @xstate/react считает машины с одинаковой конфигурацией одной и той же машиной, поэтому он сводит к минимуму повторную отрисовку, но при этом поддерживает актуальность предоставленных реализаций.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
@xstate/vue¶
useMachine() теперь возвращает snapshot вместо state и actor вместо service¶
Критическое изменение
Несовместимое изменение.
Чтобы сохранить согласованность именования с остальной частью XState и связанными с ней библиотеками:
- «состояние» теперь является «снимком»
- «сервис» теперь является «актером»
1 2 3 4 5 6 7 8 9 10 | |
1 2 3 4 5 6 7 8 9 10 | |
Новые возможности¶
- Создать системы актеров
- Новые создатели логики актеров
- Глубокое сохранение для вызванных и порожденных актеров
- Предоставить входные данные конечным автоматам и актерам
- Укажите выходные данные «готово» для актеров
- Частичные дескрипторы событий (частичные подстановочные знаки)
- Действия постановки в очередь
- Охранники более высокого уровня
- API настройки для указания типов и строго типизированных значений состояния
- Проверить API
Часто задаваемые вопросы¶
Когда Stately Studio будет совместима с XState v5?¶
В настоящее время мы работаем над совместимостью Stately Studio с XState v5. Экспорт в XState v5 (JavaScript или TypeScript) уже доступен. Мы работаем над поддержкой новых функций XState v5, таких как защита высшего порядка, частичные подстановочные знаки событий и машинный ввод/вывод.
Проголосуйте или прокомментируйте Совместимость Stately Studio + XState v5 в нашей дорожной карте, чтобы оставаться в курсе нашего прогресса.
Когда расширение XState VS Code будет совместимо с XState v5?¶
Расширение XState VS Code пока не совместимо с XState v5. Продление является для нас приоритетом, и работа уже ведется.
Проголосуйте или прокомментируйте совместимость XState v5 для расширения VS Code в нашей дорожной карте, чтобы оставаться в курсе нашего прогресса.
Когда в XState v5 появится typegen?¶
Вывод TypeScript был значительно улучшен в XState v5. Благодаря таким функциям, как API setup() и динамическим параметрам, основные варианты использования typegen больше не нужны.
Однако мы понимаем, что у typegen все еще могут быть некоторые конкретные варианты использования. Проголосуйте или прокомментируйте Typegen для XState v5 в нашей дорожной карте, чтобы оставаться в курсе нашего прогресса.
Как я могу использовать XState v4 и v5?¶
Вы можете использовать XState v4 и v5 в одном проекте, что полезно для постепенного перехода на XState v5. Чтобы использовать оба варианта, добавьте «xstate5»: «npm:xstate@5» в свой «package.json» вручную или через CLI:
1 | |
Затем вы можете импортировать версию XState v5 в свой код:
1 2 | |
Если вам нужно использовать разные версии пакета интеграции, например @xstate/react, вы можете использовать стратегию, аналогичную описанной выше, но вам нужно будет указать правильную версию XState в пакете интеграции. Это можно сделать с помощью скрипта:
1 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | |
1 2 3 4 | |
Затем вы можете использовать в своем коде совместимую с XState v5 версию @xstate/react:
1 2 3 4 5 6 | |