@@ -15,10 +15,14 @@ Actions can also be on a state’s `entry` or `exit`, also as a single action or
15
15
``` ts
16
16
import { setup } from ' xstate' ;
17
17
18
+ function trackResponse(response : string ) {
19
+ // ...
20
+ }
21
+
18
22
const feedbackMachine = setup ({
19
23
actions: {
20
- track : (_ , params : unknown ) => {
21
- track (params );
24
+ track : (_ , params : { response : string } ) => {
25
+ trackResponse (params . response );
22
26
// Tracks { response: 'good' }
23
27
},
24
28
showConfetti : () => {
@@ -62,7 +66,10 @@ Entry actions are actions that occur on any transition that enters a state node.
62
66
63
67
Entry and exit actions are defined using the ` entry: [...] ` and ` exit: [...] ` attributes on a state node. You can fire multiple entry and exit actions on a state. Top-level final states cannot have exit actions, since the machine is stopped and no further transitions can occur.
64
68
65
- <EmbedMachine embedURL = " https://stately.ai/registry/editor/embed/c447d996-cef1-421d-a422-8be695668764?mode=design&machineId=f46674a5-4da3-4aca-9900-17c6ef471f50" title = " Feedback form" />
69
+ <EmbedMachine
70
+ embedURL = " https://stately.ai/registry/editor/embed/c447d996-cef1-421d-a422-8be695668764?mode=design&machineId=f46674a5-4da3-4aca-9900-17c6ef471f50"
71
+ title = " Feedback form"
72
+ />
66
73
67
74
## Action objects
68
75
@@ -76,8 +83,10 @@ import { setup } from 'xstate';
76
83
77
84
const feedbackMachine = setup ({
78
85
actions: {
79
- track : (_ , params : unknown ) => {/* ... */ }
80
- }
86
+ track : (_ , params : { response: string }) => {
87
+ /* ... */
88
+ },
89
+ },
81
90
}).createMachine ({
82
91
// ...
83
92
states: {
@@ -113,20 +122,22 @@ const feedbackMachine = setup({
113
122
actions: {
114
123
logInitialRating : (_ , params : { initialRating: number }) => {
115
124
// ...
116
- }
117
- }
125
+ },
126
+ },
118
127
}).createMachine ({
119
128
context: {
120
- initialRating: 3
129
+ initialRating: 3 ,
121
130
},
122
- entry: [{
123
- type: ' logInitialRating' ,
124
- // highlight-start
125
- params : ({ context }) => ({
126
- initialRating: context .initialRating
127
- })
128
- // highlight-end
129
- }]
131
+ entry: [
132
+ {
133
+ type: ' logInitialRating' ,
134
+ // highlight-start
135
+ params : ({ context }) => ({
136
+ initialRating: context .initialRating ,
137
+ }),
138
+ // highlight-end
139
+ },
140
+ ],
130
141
});
131
142
```
132
143
@@ -142,17 +153,19 @@ function logInitialRating(_, params: { initialRating: number }) {
142
153
// highlight-end
143
154
144
155
const feedbackMachine = setup ({
145
- actions: { logInitialRating }
156
+ actions: { logInitialRating },
146
157
}).createMachine ({
147
158
context: { initialRating: 3 },
148
- entry: [{
149
- type: ' logInitialRating' ,
150
- // highlight-start
151
- params : ({ context }) => ({
152
- initialRating: context .initialRating
153
- })
154
- // highlight-end
155
- }]
159
+ entry: [
160
+ {
161
+ type: ' logInitialRating' ,
162
+ // highlight-start
163
+ params : ({ context }) => ({
164
+ initialRating: context .initialRating ,
165
+ }),
166
+ // highlight-end
167
+ },
168
+ ],
156
169
});
157
170
```
158
171
@@ -187,18 +200,16 @@ import { setup } from 'xstate';
187
200
const feedbackMachine = setup ({
188
201
// highlight-start
189
202
actions: {
190
- track : ({ context , event }, params ) => {
203
+ track : (_ , params : { msg : string } ) => {
191
204
// Action implementation
192
205
// ...
193
206
},
194
- }
195
- // highlight-end
196
- }).createMachine (
197
- {
198
- // Machine config
199
- entry: [{ type: ' track' , params: { msg: ' entered' }}]
200
207
},
201
- );
208
+ // highlight-end
209
+ }).createMachine ({
210
+ // Machine config
211
+ entry: [{ type: ' track' , params: { msg: ' entered' } }],
212
+ });
202
213
```
203
214
204
215
You can also provide action implementations to override existing actions in the ` machine.provide(...) ` method, which creates a new machine with the same config but with the provided implementations:
@@ -236,7 +247,7 @@ const machine = createMachine({
236
247
// This action creator only returns an action object
237
248
// like { type: 'xstate.assign', ... }
238
249
assign ({ count: context .count + 1 });
239
- }
250
+ },
240
251
// highlight-end
241
252
});
242
253
@@ -245,8 +256,8 @@ const machine = createMachine({
245
256
context: { count: 0 },
246
257
// highlight-start
247
258
entry: assign ({
248
- count : ({ context }) => context .count + 1
249
- })
259
+ count : ({ context }) => context .count + 1 ,
260
+ }),
250
261
// highlight-end
251
262
});
252
263
@@ -256,9 +267,9 @@ const machine = createMachine({
256
267
// highlight-start
257
268
entry: enqueueActions (({ context , enqueue }) => {
258
269
enqueue .assign ({
259
- count: context .count + 1
270
+ count: context .count + 1 ,
260
271
});
261
- })
272
+ }),
262
273
// highlight-end
263
274
});
264
275
```
@@ -276,8 +287,8 @@ import { setup } from 'xstate';
276
287
277
288
const countMachine = setup ({
278
289
types: {
279
- events: {} as { type: ' increment' ; value: number }
280
- }
290
+ events: {} as { type: ' increment' ; value: number },
291
+ },
281
292
}).createMachine ({
282
293
context: {
283
294
count: 0 ,
@@ -314,8 +325,8 @@ import { setup } from 'xstate';
314
325
315
326
const countMachine = setup ({
316
327
types: {
317
- events: {} as { type: ' increment' ; value: number }
318
- }
328
+ events: {} as { type: ' increment' ; value: number },
329
+ },
319
330
}).createMachine ({
320
331
context: {
321
332
count: 0 ,
@@ -373,14 +384,13 @@ const machine = createMachine({
373
384
entry: raise (({ context , event }) => ({
374
385
type: ' dynamicEvent' ,
375
386
data: context .someValue ,
376
- }))
387
+ })),
377
388
// highlight-end
378
389
});
379
390
```
380
391
381
392
Events can also be raised with a delay, which will not place them in the internal event queue, since they will not be immediately processed:
382
393
383
-
384
394
``` ts
385
395
import { createMachine , raise } from ' xstate' ;
386
396
@@ -496,18 +506,17 @@ import { createMachine, sendTo } from 'xstate';
496
506
497
507
const childMachine = createMachine ({
498
508
context : ({ input }) => ({
499
- parentRef: input .parentRef
509
+ parentRef: input .parentRef ,
500
510
}),
501
511
on: {
502
512
someEvent: {
503
513
// highlight-start
504
- actions: sendTo (
505
- ({ context }) => context .parentRef ,
506
- { type: ' tellParentSomething' }
507
- ),
514
+ actions: sendTo (({ context }) => context .parentRef , {
515
+ type: ' tellParentSomething' ,
516
+ }),
508
517
// highlight-end
509
- }
510
- }
518
+ },
519
+ },
511
520
});
512
521
513
522
const parentMachine = createMachine ({
@@ -517,17 +526,17 @@ const parentMachine = createMachine({
517
526
src: childMachine ,
518
527
// highlight-start
519
528
input : ({ self }) => ({
520
- parentRef: self
521
- })
529
+ parentRef: self ,
530
+ }),
522
531
// highlight-end
523
532
},
524
533
on: {
525
534
tellParentSomething: {
526
535
actions : () => {
527
536
console .log (' Child actor told parent something' );
528
- }
529
- }
530
- }
537
+ },
538
+ },
539
+ },
531
540
});
532
541
533
542
const parentActor = createActor (parentMachine );
@@ -537,46 +546,69 @@ parentActor.start();
537
546
538
547
</details >
539
548
540
- :::
549
+ <details >
550
+ <summary >Example using input (TypeScript):</summary >
541
551
542
552
``` ts
543
- import { createMachine , sendParent } from ' xstate' ;
553
+ import { ActorRef , createActor , log , sendTo , setup , Snapshot } from ' xstate' ;
544
554
545
- const childMachine = createMachine ({
546
- on: {
547
- someEvent: {
548
- // highlight-start
549
- actions: sendParent ({ type: ' tellParentSomething' }),
550
- // highlight-end
551
- }
552
- }
555
+ // highlight-start
556
+ type ChildEvent = {
557
+ type: ' tellParentSomething' ;
558
+ data? : string ;
559
+ };
560
+ type ParentActor = ActorRef <Snapshot <unknown >, ChildEvent >;
561
+ // highlight-end
562
+
563
+ const childMachine = setup ({
564
+ types: {
565
+ context: {} as {
566
+ parentRef: ParentActor
567
+ },
568
+ input: {} as {
569
+ parentRef: ParentActor ;
570
+ },
571
+ },
572
+ }).createMachine ({
573
+ context : ({ input : { parentRef } }) => ({parentRef }),
574
+ // highlight-start
575
+ entry: sendTo (({ context }) => context .parentRef , {
576
+ type: ' tellParentSomething' ,
577
+ data: ' Hi parent!' ,
578
+ }),
579
+ // highlight-end
553
580
});
554
581
555
- const parentMachine = createMachine ({
556
- // ...
582
+ export const parent = setup ({
583
+ actors: { child: childMachine },
584
+ }).createMachine ({
585
+ // highlight-start
557
586
invoke: {
558
- id: ' child' ,
559
- src: childMachine
587
+ src: ' child' ,
588
+ input : ({ self }) => ({
589
+ parentRef: self ,
590
+ }),
560
591
},
592
+ // highlight-end
561
593
on: {
562
594
tellParentSomething: {
563
- actions : () => {
564
- console .log (' Child actor told parent something' );
565
- }
566
- }
567
- }
595
+ actions: log ( ({event :{data }})=> ` Child actor says "${data }" ` ),
596
+ },
597
+ },
568
598
});
569
599
570
- const parentActor = createActor (parentMachine );
571
-
572
- parentActor .start ();
600
+ createActor (parent ).start ();
573
601
```
602
+ </details >
603
+
604
+ :::
574
605
575
606
## Enqueue actions
576
607
577
608
The ` enqueueActions(...) ` action creator is a higher-level action that enqueues actions to be executed sequentially, without actually executing any of the actions. It takes a callback that receives the ` context ` , ` event ` as well as ` enqueue ` and ` check ` functions:
578
609
579
610
- The ` enqueue(...) ` function is used to enqueue an action. It takes an action object or action function:
611
+
580
612
``` ts
581
613
actions : enqueueActions (({ enqueue }) => {
582
614
// Enqueue an action object
@@ -587,15 +619,16 @@ The `enqueueActions(...)` action creator is a higher-level action that enqueues
587
619
588
620
// Enqueue a simple action with no params
589
621
enqueue (' doSomething' );
590
- })
622
+ });
591
623
```
624
+
592
625
- The ` check(...) ` function is used to conditionally enqueue an action. It takes a guard object or a guard function and returns a boolean that represents whether the guard evaluates to ` true ` :
593
626
``` ts
594
627
actions : enqueueActions (({ enqueue , check }) => {
595
628
if (check ({ type: ' everythingLooksGood' })) {
596
629
enqueue (' doSomething' );
597
630
}
598
- })
631
+ });
599
632
```
600
633
- There are also helper methods on ` enqueue ` for enqueueing built-in actions:
601
634
- ` enqueue.assign(...) ` : Enqueues an ` assign(...) ` action
@@ -613,7 +646,7 @@ const machine = createMachine({
613
646
entry: enqueueActions (({ context , event , enqueue , check }) => {
614
647
// assign action
615
648
enqueue .assign ({
616
- count: context .count + 1
649
+ count: context .count + 1 ,
617
650
});
618
651
619
652
// Conditional actions (replaces choose(...))
@@ -637,7 +670,7 @@ const machine = createMachine({
637
670
}
638
671
639
672
// no return
640
- })
673
+ }),
641
674
});
642
675
```
643
676
@@ -656,15 +689,15 @@ const machine = setup({
656
689
// highlight-end
657
690
greet : (_ , params : { name: string }) => {
658
691
console .log (` Hello ${params .name }! ` );
659
- }
660
- }
692
+ },
693
+ },
661
694
}).createMachine ({
662
695
// ...
663
696
// highlight-start
664
697
entry: {
665
698
type: ' doThings' ,
666
- params: { name: ' World' }
667
- }
699
+ params: { name: ' World' },
700
+ },
668
701
// highlight-end
669
702
});
670
703
```
@@ -693,7 +726,6 @@ You can create state machines with the `log(...)` action in our drag-and-drop St
693
726
694
727
:::
695
728
696
-
697
729
## Cancel action
698
730
699
731
The ` cancel(...) ` action cancels a delayed ` sendTo(...) ` or ` raise(...) ` action by their IDs:
@@ -779,7 +811,6 @@ const countMachine = createMachine({
779
811
For simple actions, you can specify an action string instead of an action object. Though we prefer using objects for consistency.
780
812
781
813
``` ts
782
-
783
814
import { createMachine } from ' xstate' ;
784
815
785
816
const feedbackMachine = createMachine ({
@@ -797,14 +828,13 @@ const feedbackMachine = createMachine({
797
828
},
798
829
},
799
830
});
800
-
801
831
```
802
832
803
833
## Actions and TypeScript
804
834
805
835
:::typescript
806
836
807
- ** XState v5 requires TypeScript version 5.0 or greater.**
837
+ ** XState v5 requires TypeScript version 5.0 or greater.**
808
838
809
839
For best results, use the latest TypeScript version. [ Read more about XState and TypeScript] ( typescript.mdx )
810
840
@@ -825,15 +855,15 @@ const machine = setup({
825
855
},
826
856
increment : (_ , params : { value: number }) => {
827
857
// ...
828
- }
829
- }
858
+ },
859
+ },
830
860
// highlight-end
831
861
}).createMachine ({
832
862
// ...
833
863
entry: [
834
864
{ type: ' track' , params: { response: ' good' } },
835
865
{ type: ' increment' , params: { value: 1 } },
836
- ]
866
+ ],
837
867
});
838
868
```
839
869
@@ -878,11 +908,11 @@ const machine = createMachine({
878
908
states: {
879
909
start: {
880
910
// highlight-start
881
- entry: [{ type:' startEntryAction' }],
882
- exit: [{ type:' startExitAction' }],
911
+ entry: [{ type: ' startEntryAction' }],
912
+ exit: [{ type: ' startExitAction' }],
883
913
// highlight-end
884
- }
885
- }
914
+ },
915
+ },
886
916
});
887
917
```
888
918
@@ -899,9 +929,9 @@ const machine = createMachine({
899
929
{ type: ' doSomething' },
900
930
{ type: ' doSomethingElse' },
901
931
// highlight-end
902
- ]
903
- }
904
- }
932
+ ],
933
+ },
934
+ },
905
935
});
906
936
```
907
937
@@ -917,11 +947,11 @@ const machine = createMachine({
917
947
// highlight-start
918
948
({ context , event }) => {
919
949
console .log (context , event );
920
- }
950
+ },
921
951
// highlight-end
922
- ]
923
- }
924
- }
952
+ ],
953
+ },
954
+ },
925
955
});
926
956
```
927
957
@@ -932,20 +962,20 @@ import { setup } from 'xstate';
932
962
933
963
const someAction = () => {
934
964
// ...
935
- }
965
+ };
936
966
937
967
const machine = setup ({
938
968
actions: {
939
- someAction
940
- }
969
+ someAction ,
970
+ },
941
971
}).createMachine ({
942
972
entry: [
943
973
// highlight-start
944
- { type: ' someAction' }
974
+ { type: ' someAction' },
945
975
// highlight-end
946
976
],
947
977
// ...
948
- })
978
+ });
949
979
```
950
980
951
981
### Cheatsheet: providing actions
@@ -955,20 +985,20 @@ import { setup } from 'xstate';
955
985
956
986
const someAction = () => {
957
987
// ...
958
- }
988
+ };
959
989
960
990
const machine = setup ({
961
991
actions: {
962
- someAction
963
- }
992
+ someAction ,
993
+ },
964
994
}).createMachine ({
965
995
// ...
966
996
});
967
997
968
998
const modifiedMachine = machine .provide ({
969
999
someAction : () => {
970
1000
// Overridden action implementation
971
- }
1001
+ },
972
1002
});
973
1003
```
974
1004
@@ -989,7 +1019,7 @@ const countMachine = createMachine({
989
1019
actions: assign ({
990
1020
count : ({ context , event }) => {
991
1021
return context .count + event .value ;
992
- }
1022
+ },
993
1023
}),
994
1024
// highlight-end
995
1025
},
@@ -1011,7 +1041,7 @@ const countMachine = createMachine({
1011
1041
// highlight-start
1012
1042
actions: assign (({ context , event }) => {
1013
1043
return {
1014
- count: context .count + event .value
1044
+ count: context .count + event .value ,
1015
1045
};
1016
1046
}),
1017
1047
// highlight-end
@@ -1065,13 +1095,13 @@ const machine = createMachine({
1065
1095
}
1066
1096
1067
1097
enqueue .assign ({
1068
- count: 0
1069
- })
1098
+ count: 0 ,
1099
+ });
1070
1100
1071
1101
enqueue .sendTo (' someActor' , { type: ' someEvent' });
1072
1102
1073
- enqueue .raise ({ type: ' anEvent' })
1074
- })
1103
+ enqueue .raise ({ type: ' anEvent' });
1104
+ }),
1075
1105
// highlight-end
1076
1106
});
1077
1107
```
0 commit comments