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

Начнём

Наш первый конечный автомат

Предположим, мы хотим смоделировать Promise как конечный автомат. Сначала установите XState с помощью NPM или Yarn:

1
npm install xstate --save

Если вы используете VSCode, вам следует установить наше расширение VSCode, чтобы вы могли визуализировать автомат, который вы строите, в процессе работы.

Затем в своем проекте импортируйте createMachine — функцию, которая создает конечный автомат.

1
2
3
import { createMachine } from 'xstate';

const promiseMachine = createMachine(/* ... */);

Мы передадим конфигурацию автомата createMachine. Нам потребуется предоставить:

  • id — для идентификации автомата
  • initial — для указания узла начального состояния, в котором должен находиться этот автомат
  • states — для определения каждого из дочерних состояний:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import { createMachine } from 'xstate';

const promiseMachine = createMachine({
    id: 'promise',
    initial: 'pending',
    states: {
        pending: {},
        resolved: {},
        rejected: {},
    },
});

Затем нам нужно добавить переходы к узлам состояния.

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

const promiseMachine = createMachine({
    id: 'promise',
    initial: 'pending',
    states: {
        pending: {
            on: {
                RESOLVE: { target: 'resolved' },
                REJECT: { target: 'rejected' },
            },
        },
        resolved: {},
        rejected: {},
    },
});

Нам также нужно пометить узлы состояния resolved и rejected, как узлы конечного состояния, поскольку автомат Promise прекращает работу, как только достигает этих состояний:

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

const promiseMachine = createMachine({
    id: 'promise',
    initial: 'pending',
    states: {
        pending: {
            on: {
                RESOLVE: { target: 'resolved' },
                REJECT: { target: 'rejected' },
            },
        },
        resolved: {
            type: 'final',
        },
        rejected: {
            type: 'final',
        },
    },
});

Теперь наш конечный автомат готов к визуализации. Вы можете скопировать / вставить приведенный выше код и визуализировать его в Stately Viz. Вот как это будет выглядеть:

Запуск нашего автомата

То, как мы запускаем наш автомат, зависит от того, где мы планируем его использовать.

В Node.js или Vanilla JS

Чтобы интерпретировать автомат и заставить его работать, нам нужно добавить интерпретатор. Этот код создает службу:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import { createMachine, interpret } from 'xstate';

const promiseMachine = createMachine({
    /* ... */
});

const promiseService = interpret(
    promiseMachine
).onTransition((state) => console.log(state.value));

// Start the service
promiseService.start();
// => 'pending'

promiseService.send({ type: 'RESOLVE' });
// => 'resolved'

В React

Если бы мы хотели использовать наш автомат внутри компонента React, мы могли бы использовать хук useMachine:

Дополнительно нам нужно установить пакет @xstate/react

 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
import { useMachine } from '@xstate/react';

const Component = () => {
    const [state, send] = useMachine(promiseMachine);

    return (
        <div>
            {/** You can listen to what state the service is in */}
            {state.matches('pending') && <p>Loading...</p>}
            {state.matches('rejected') && (
                <p>Promise Rejected</p>
            )}
            {state.matches('resolved') && (
                <p>Promise Resolved</p>
            )}
            <div>
                {/** You can send events to the running service */}
                <button onClick={() => send('RESOLVE')}>
                    Resolve
                </button>
                <button onClick={() => send('REJECT')}>
                    Reject
                </button>
            </div>
        </div>
    );
};

Комментарии