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

События

Событие (event) — это то, что заставляет конечный автомат переходить из текущего состояния в следующее состояние.

API

Событие — это объект со свойством type, указывающим, к какому типу оно относится:

1
2
3
const timerEvent = {
  type: 'TIMER', // the convention is to use CONST_CASE for event names
};

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

1
2
// equivalent to { type: 'TIMER' }
const timerEvent = 'TIMER';

Объекты событий также могут иметь другие свойства, которые представляют данные, связанные с событием:

1
2
3
4
const keyDownEvent = {
  type: 'keydown',
  key: 'Enter',
};

Отправка событий

Переход определяет, каким будет следующее состояние, учитывая текущее состояние и событие, определенные в его свойстве on: {...}. Это можно увидеть, передав событие в метод перехода:

 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 lightMachine = createMachine({
  /* ... */
});

const { initialState } = lightMachine;

let nextState = lightMachine.transition(
  initialState,
  'TIMER'
); // string event
console.log(nextState.value);
// => 'yellow'

nextState = lightMachine.transition(nextState, {
  type: 'TIMER',
}); // event object
console.log(nextState.value);
// => 'red'

Многие нативные события, такие как события DOM, совместимы и могут использоваться напрямую с XState, указав тип события в свойстве type:

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

const mouseMachine = createMachine({
  on: {
    mousemove: {
      actions: [
        (context, event) => {
          const { offsetX, offsetY } = event;
          console.log({ offsetX, offsetY });
        },
      ],
    },
  },
});
const mouseService = interpret(mouseMachine).start();

window.addEventListener('mousemove', (event) => {
  // event can be sent directly to service
  mouseService.send(event);
});

Нулевые события

Внимание

Синтаксис нулевого события ({on: {'': ...}}) будет устаревшим в версии 5. Вместо него следует использовать новый синтаксис always.

Нулевое событие (null 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
25
26
27
// contrived example
const skipMachine = createMachine({
  id: 'skip',
  initial: 'one',
  states: {
    one: {
      on: { CLICK: 'two' },
    },
    two: {
      // null event '' always occurs once state is entered
      // immediately take the transition to 'three'
      on: { '': 'three' },
    },
    three: {
      type: 'final',
    },
  },
});

const { initialState } = skipMachine;
const nextState = skipMachine.transition(
  initialState,
  'CLICK'
);

console.log(nextState.value);
// => 'three'

Существует много вариантов использования нулевых событий, особенно при определении переходов, когда (потенциально проходное) состояние сразу определяет, какое следующее состояние должно быть основано на защитных функциях:

 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
const isAdult = ({ age }) => age >= 18;
const isMinor = ({ age }) => age < 18;

const ageMachine = createMachine({
  id: 'age',
  context: { age: undefined }, // age unknown
  initial: 'unknown',
  states: {
    unknown: {
      on: {
        // immediately take transition that satisfies conditional guard.
        // otherwise, no transition occurs
        '': [
          { target: 'adult', cond: isAdult },
          { target: 'child', cond: isMinor },
        ],
      },
    },
    adult: { type: 'final' },
    child: { type: 'final' },
  },
});

console.log(ageMachine.initialState.value);
// => 'unknown'

const personData = { age: 28 };

const personMachine = ageMachine.withContext(personData);

console.log(personMachine.initialState.value);
// => 'adult'

Комментарии