Входные данные Input (входные данные) — это данные, предоставляемые конечному автомату, которые влияют на его поведение. В XState вы предоставляете input при создании актора , используя второй аргумент функции createActor(machine, { 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 import { createActor , setup } from 'xstate' ;
const feedbackMachine = setup ({
types : {
context : {} as {
userId : string ;
feedback : string ;
rating : number ;
},
// highlight-start
input : {} as {
userId : string ;
defaultRating : number ;
},
// highlight-end
},
}). createMachine ({
// highlight-next-line
context : ({ input }) => ({
// highlight-next-line
userId : input.userId ,
feedback : '' ,
// highlight-next-line
rating : input.defaultRating ,
}),
// ...
});
const feedbackActor = createActor ( feedbackMachine , {
// highlight-start
input : {
userId : '123' ,
defaultRating : 5 ,
},
// highlight-end
});
Вы можете передать input любому виду актора, прочитав эти входные данные из свойства input первого аргумента создателей логики актора, таких как fromPromise(), fromTransition(), fromObservable() и других.
Input с fromPromise():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import { createActor , fromPromise } from 'xstate' ;
const userFetcher = fromPromise (
({ input } : { input : { userId : string } }) => {
return fetch ( `/users/ ${ input . userId } ` ). then (( res ) =>
res . json ()
);
}
);
const userFetcherActor = createActor ( userFetcher , {
// highlight-start
input : {
userId : '123' ,
},
// highlight-end
}). start ();
userFetcherActor . onDone (( data ) => {
console . log ( data );
// выводит данные пользователя для userId 123
});
Input с fromTransition():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 import { createActor , fromTransition } from 'xstate' ;
const counter = fromTransition (( state , event )) => {
if ( event . type === 'INCREMENT' ) {
return { count : state.count + 1 };
}
return state ;
}, ({ input } : { input : { startingCount? : number } }) => ({
count : input.startingCount ?? 0 ,
});
const counterActor = createActor ( counter , {
// highlight-start
input : {
startingCount : 10 ,
}
});
Input с fromObservable():
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import { createActor , fromObservable } from 'xstate' ;
import { interval } from 'rxjs' ;
const intervalLogic = fromObservable (
({ input } : { input : { interval : number } }) => {
return interval ( input . interval );
}
);
const intervalActor = createActor ( intervalLogic , {
// highlight-start
input : {
interval : 1000 ,
},
// highlight-end
});
intervalActor . start ();
Когда актор запускается, он автоматически отправляет себе специальное событие с именем xstate.init. Если input предоставлен в функцию createActor(logic, { input }), он будет включён в событие xstate.init:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import { createActor , createMachine } from 'xstate' ;
const feedbackMachine = createMachine ({
// highlight-start
entry : ({ event }) => {
console . log ( event . input );
// выводит { userId: '123', defaultRating: 5 }
},
// highlight-end
// ...
});
const feedbackActor = createActor ( feedbackMachine , {
input : {
userId : '123' ,
defaultRating : 5 ,
},
}). start ();
Вы можете предоставить input вызванным акторам через свойство input конфигурации invoke:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import { createActor , setup } from 'xstate' ;
const feedbackMachine = setup ({
actors : {
liveFeedback : fromPromise (
({ input } : { input : { domain : string } }) => {
return fetch (
`https:// ${ input . domain } /feedback`
). then (( res ) => res . json ());
}
),
},
}). createMachine ({
invoke : {
src : 'liveFeedback' ,
// highlight-start
input : {
domain : 'stately.ai' ,
},
// highlight-end
},
});
Свойство invoke.input может быть статическим входным значением или функцией, возвращающей входное значение. Функция будет вызвана с объектом, содержащим текущий 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
25
26
27 import { createActor , setup } from 'xstate' ;
const feedbackMachine = setup ({
actors : {
// highlight-start
fetchUser : fromPromise (({ input }) => {
return fetch (
`/users/ ${ input . userId } `
). then (( res ) => res . json ());
}),
// highlight-end
},
}). createMachine ({
context : {
userId : '' ,
feedback : '' ,
rating : 0 ,
},
invoke : {
src : 'fetchUser' ,
// highlight-next-line
input : ({ context }) => ({
userId : context.userId ,
}),
},
// ...
});
Вы можете предоставить input порождённым акторам через свойство input конфигурации spawn:
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 import { createActor , setup , type AnyActorRef } from 'xstate' ;
const feedbackMachine = setup ({
types : {
context : {} as {
userId : string ;
feedback : string ;
rating : number ;
emailRef : AnyActorRef ;
},
},
actors : {
// highlight-start
emailUser : fromPromise (({ input } : { input : { userId : string } }) => {
return fetch ( `/users/ ${ input . userId } ` , {
method : 'POST' ,
// ...
});
}),
// highlight-end
},
}). createMachine ({
context : {
userId : '' ,
feedback : '' ,
rating : 0 ,
emailRef : null ,
},
// ...
on : {
'feedback.submit' : {
actions : assign ({
emailRef : ({ context , spawn }) => {
return spawn ( 'emailUser' , {
// highlight-next-line
input : { userId : context.userId },
});
},
}),
},
},
// ...
});
Варианты использования 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 // Старый способ: использование фабричной функции
const createFeedbackMachine = ( userId , defaultRating ) => {
return createMachine ({
context : {
userId ,
feedback : '' ,
rating : defaultRating ,
},
// ...
});
};
const feedbackMachine1 = createFeedbackMachine ( '123' , 5 );
const feedbackActor1 = createActor (
feedbackMachine1
). start ();
// Новый способ: использование input
const feedbackMachine = createMachine ({
context : ({ input }) => ({
userId : input.userId ,
feedback : '' ,
rating : input.defaultRating ,
}),
// ...
});
const feedbackActor = createActor ( feedbackMachine , {
input : {
userId : '123' ,
defaultRating : 5 ,
},
});
Передача новых данных актору Изменение input не приведёт к перезапуску актора. Вам нужно отправить событие актору, чтобы передать новые данные:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 const Component = ( props ) => {
const feedbackActor = useActor ( feedbackMachine , {
input : {
userId : props.userId ,
defaultRating : props.defaultRating ,
},
});
useEffect (() => {
feedbackActor . send ({
type : 'userId.change' ,
userId : props.userId ,
});
}, [ props . userId ]);
// ...
};
TypeScript
XState v5 требует TypeScript версии 5.0 или выше.
Для лучших результатов используйте последнюю версию TypeScript. Подробнее о XState и TypeScript
Вы можете строго типизировать input вашего автомата в свойстве types.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 import { createActor , setup } from 'xstate' ;
const machine = setup ({
types : {
// highlight-start
input : {} as {
userId : string ;
defaultRating : number ;
};
// highlight-end
context : {} as {
userId : string ;
feedback : string ;
rating : number ;
};
},
}). createMachine ({
context : ({ input }) => ({
userId : input.userId ,
feedback : '' ,
rating : input.defaultRating ,
}),
});
const actor = createActor ( machine , {
input : {
userId : '123' ,
defaultRating : 5 ,
},
});
Используйте нашу шпаргалку по input XState ниже для быстрого начала.
const feedbackActor = createActor ( feedbackMachine , {
input : {
userId : '123' ,
defaultRating : 5 ,
},
});
const feedbackMachine = createMachine ({
invoke : {
src : 'liveFeedback' ,
input : {
domain : 'stately.ai' ,
},
},
});
const feedbackMachine = createMachine ({
context : {
userId : 'some-user-id' ,
},
invoke : {
src : 'fetchUser' ,
input : ({ context }) => ({
userId : context.userId ,
}),
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 const feedbackMachine = createMachine ({
types : {
events :
| { type : 'messageSent' ; message : string }
| { type : 'incremented' ; count : number },
},
invoke : {
src : 'fetchUser' ,
input : ({ event }) => {
// highlight-next-line
assertEvent ( event , 'messageSent' );
return {
message : event.message ,
};
},
},
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 const feedbackMachine = createMachine ({
context : {
userId : '' ,
},
// ...
on : {
'feedback.submit' : {
actions : assign ({
emailRef : ({ context , spawn }) => {
return spawn ( 'emailUser' , {
input : { userId : context.userId },
});
},
}),
},
},
// ...
});