Перейти к содержанию

Параллельные состояния

В диаграммах состояний параллельное состояние — это состояние, которое имеет несколько дочерних состояний (также известных как регионы), которые все активны одновременно. Это отличается от родительского состояния, где только одно дочернее состояние активно в каждый момент времени.

Параллельные состояния имеют следующие характеристики:

  • Вход в параллельное состояние также одновременно входит во все его регионы.
  • Выход из параллельного состояния также одновременно выходит из всех его регионов.
  • Событие, полученное в параллельном состоянии, одновременно получается и обрабатывается всеми его регионами.

Вот пример музыкального плеера с параллельным состоянием, состоящим из двух регионов: один для управления воспроизведением трека и один для управления громкостью:

 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
import { createMachine, assign } from 'xstate';

const playerMachine = createMachine({
    id: 'player',
    type: 'parallel',
    states: {
        track: {
            initial: 'paused',
            states: {
                paused: {
                    on: { PLAY: 'playing' },
                },
                playing: {
                    on: { STOP: 'paused' },
                },
            },
        },
        volume: {
            initial: 'normal',
            states: {
                normal: {
                    on: { MUTE: 'muted' },
                },
                muted: {
                    on: { UNMUTE: 'normal' },
                },
            },
        },
    },
});

Значение параллельного состояния

Значение состояния параллельного состояния — это объект со значениями состояний каждого из его регионов.

1
2
3
4
5
6
7
8
9
const playerActor = createActor(playerMachine);
playerActor.start();

console.log(playerActor.getSnapshot().value);
// выводит объект:
// {
//   track: 'paused',
//   volume: 'normal'
// }

Переход onDone в параллельном состоянии

Когда все регионы параллельного состояния достигли своих финальных состояний, выполняется переход onDone параллельного состояния.

В этом примере переход onDone параллельного состояния выполняется, когда оба региона достигли своих финальных состояний; то есть когда 'grindingBeans' достигает состояния 'grindingBeans.beansGround', а 'boilingWater' достигает состояния 'boilingWater.waterBoiled'.

 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
import { createMachine } from 'xstate';

export const machine = createMachine({
    id: 'coffee',
    initial: 'preparing',
    states: {
        preparing: {
            states: {
                grindBeans: {
                    initial: 'grindingBeans',
                    states: {
                        grindingBeans: {
                            on: {
                                BEANS_GROUND: {
                                    target: 'beansGround',
                                },
                            },
                        },
                        beansGround: {
                            type: 'final',
                        },
                    },
                },
                boilWater: {
                    initial: 'boilingWater',
                    states: {
                        boilingWater: {
                            on: {
                                WATER_BOILED: {
                                    target: 'waterBoiled',
                                },
                            },
                        },
                        waterBoiled: {
                            type: 'final',
                        },
                    },
                },
            },
            type: 'parallel',
            onDone: {
                target: 'makingCoffee',
            },
        },
        makingCoffee: {},
    },
});

Моделирование

При моделировании с параллельными состояниями есть несколько важных соображений, которые следует учитывать:

Лучшие практики

  • Избегайте переходов между регионами: Каждый регион в параллельном состоянии должен быть независимым и не переходить напрямую в состояния других регионов. Это поддерживает разделение ответственности и предотвращает сложные взаимозависимости.

  • Используйте для связанных задач: Параллельные состояния идеальны для моделирования аспектов системы, которые связаны, но работают независимо. Например:

    • Состояние воспроизведения медиаплеера и управление громкостью
    • Состояние валидации формы и состояние отправки
    • Состояние игрока и состояние игры
  • Учитывайте синхронизацию: Хотя регионы работают независимо, им может потребоваться координация. Используйте события, которые могут обрабатываться несколькими регионами, для достижения синхронизации при необходимости.

Когда использовать параллельные состояния

  • Когда у вас есть несколько независимых аспектов системы, которые нужно отслеживать одновременно
  • Когда эти аспекты могут нуждаться в координации или влиять друг на друга
  • Когда система должна поддерживать несколько активных состояний одновременно

Когда использовать альтернативы

  • Используйте invoke вместо этого, когда задачи полностью отделены и не нуждаются в координации
  • Используйте вложенные состояния, когда состояния иерархичны и только одно должно быть активно в каждый момент
  • Используйте одно состояние с несколькими свойствами, когда аспекты тесно связаны

Примеры использования

  • Пользовательский интерфейс: Управление несколькими независимыми состояниями UI (например, боковая панель, модальное окно и основной контент)
  • Разработка игр: Одновременное отслеживание состояния игрока, состояния игры и состояния UI
  • Обработка форм: Параллельное управление валидацией, отправкой и состояниями ошибок
  • Медиаплееры: Независимое управление воспроизведением, громкостью и состояниями плейлиста

Шпаргалка по параллельным состояниям

Шпаргалка: создание параллельного состояния

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { createMachine } from 'xstate';

const machine = createMachine({
    // ...
    states: {
        type: 'parallel',
        states: {
            one: {
                /* ... */
            },
            two: {
                /* ... */
            },
            three: {
                /* ... */
            },
        },
        onDone: {
            // Выполняется, когда все регионы достигли своих финальных состояний
        },
    },
});

Комментарии