My definition for XState FMS in the file task_statemachine.js
is as follows:
module.exports = {
id: 'runner',
initial: 'setup',
states: {
setup: {
on: {
RECEIVED: {
target: 'running',
actions: 'runTask',
},
ERROR: {
target: 'error',
actions: 'taskError',
},
TERMINATED: {
target: 'terminated',
actions: 'terminate',
},
},
},
running: {
on: {
COMPLETE: {
target: 'complete',
actions: 'taskComplete',
},
ERROR: {
target: 'error',
actions: 'taskError',
},
TERMINATED: {
target: 'terminated',
actions: 'terminate',
},
},
},
terminated: {
type: 'final',
},
complete: {
type: 'final',
},
error: {
type: 'final',
},
},
}
The actual machine itself and service are created in the constructor of the TASK()
class like this:
if (!this.state) this.state = interpret(Machine(require('./task_statemachine'), {
actions: {
runTask: this.runTask,
taskComplete: this.taskComplete,
taskError: this.taskError,
terminate: this.terminate
}
})).start();
I have a problem when trying to run actions which are supposed to call the functions defined in the class. I'm sending the events in the following way this.state.send('COMPLETE');
If I define actions
as array of callbacks, like this runTask: this.runTask()
the actions seemingly run as they should. According to my colleagues it's a bad practice to do so. What the correct way to invoke the actions once the class in loaded?
The issue was caused by this
binding. The solution was to warp the function callback into an arrow function in the actions array.
if (!this.state) this.state = interpret(Machine(require('./task_statemachine'), {
actions: {
// High Level Functions
runTask: () => {
this.runTask()
},
taskComplete: () => {
this.taskComplete()
},
taskError: () => {
this.taskError()
},
terminate: () => {
this.terminate()
}
// runTask() Functions
}
})).start();