Home > Net >  Method referenced in XState machine is not callable within class but works when declared as global
Method referenced in XState machine is not callable within class but works when declared as global

Time:09-09

Why cannot I reference a method declared within the same class as XState service? If I move the method outside of the class, it works fine.

export class LoaderMachine {
    service = interpret(createMachine<LoaderContext, LoaderEvent, LoaderState>(
        {
        .....
        }, {
            actions: {
                fetch() {
                    this.fetchDataInsideClass(); // not callable
                    fetchData(); // global declaration works
                },
                restart() {
                    console.log('Recovering from error')
                    service.send('RESTART');
                },
                finished(context, event) {
                    console.log('Done');
                }
            }
        }));

    async fetchDataInsideClass() {
        try {
            console.log('Started');
            service.send('SUCCESS');
        } catch (err) {
            console.error(`Failed with ${err}`);
            service.send('ERROR');
        }
    }
}

async function fetchData() {
    try {
        console.log('Started');
        service.send('SUCCESS');
    } catch (err) {
        console.error(`Failed with ${err}`);
        service.send('ERROR');
    }
}

Results in a compilation error:

TS2349: This expression is not callable.
Not all constituents of type 'AssignActionObject<LoaderContext, LoaderEvent> | ActionObject<LoaderContext, LoaderEvent> | ActionFunction<...>' are callable.     
Type 'AssignActionObject<LoaderContext, LoaderEvent>' has no call signatures

CodePudding user response:

The problem in your sample code is that actions.fetch is a function declaration that will set its execution context (the this binding) in the runtime depending on how it's called. For more information, check out the MDN reference.

A quick fix is to declare actions.fetch (and all the other action implementations) as an arrow function that will be bound to the instance of LoaderMachine class.

actions: {
    fetch: () => {
      this.fetchDataInsideClass(); // not callable
      fetchData(); // global declaration works
    },
    restart: () => {
      console.log("Recovering from error");
      service.send("RESTART");
    },
    finished: (context, event) => {
      console.log("Done");
    },
  },
  • Related