XState服务中无法调用类内方法,全局方法运行正常?
为何XState服务的actions中无法调用类内声明的方法,全局方法却能正常运行?
问题概述
在LoaderMachine类中,XState服务的actions配置里的fetch方法尝试调用类内的fetchDataInsideClass时触发编译错误,但调用类外的全局方法fetchData却能正常执行。
代码示例
export class LoaderMachine { service = interpret(createMachine<LoaderContext, LoaderEvent, LoaderState>( { ..... }, { actions: { fetch() { this.fetchDataInsideClass(); // 无法调用 fetchData(); // 全局方法可正常运行 }, 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'); } }
编译错误信息
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
原因分析
- this指向异常:XState执行
actions中的普通函数时,函数内部的this并不会指向LoaderMachine的实例,而是指向XState内部的执行上下文(或严格模式下为undefined)。此时this.fetchDataInsideClass根本不是类中定义的方法,自然无法调用。 - 类型不匹配:TypeScript检测到
this.fetchDataInsideClass不符合XState Action的类型要求,因此抛出类型错误。 - 全局方法能运行的原因:全局方法
fetchData不依赖类实例的this,直接访问全局作用域中的service(尽管这种写法存在隐患,正确的做法应该是使用类实例的service),所以能正常执行。
解决方案
方案1:使用箭头函数绑定this
箭头函数会捕获外层作用域的this(即LoaderMachine的实例),修改actions中的fetch方法为箭头函数:
actions: { fetch: () => { this.fetchDataInsideClass(); // 此时this指向类实例 }, // 其他action保持不变 }
方案2:修正类内方法的service访问
同时,类内的fetchDataInsideClass方法中应该使用类实例的service,而不是全局service,避免作用域问题:
async fetchDataInsideClass() { try { console.log('Started'); this.service.send('SUCCESS'); // 使用this.service } catch (err) { console.error(`Failed with ${err}`); this.service.send('ERROR'); } }
方案3:在构造函数中绑定this
如果偏好使用普通函数,可以在类的构造函数中手动绑定this:
export class LoaderMachine { service; constructor() { this.fetch = this.fetch.bind(this); this.service = interpret(createMachine<LoaderContext, LoaderEvent, LoaderState>( { ..... }, { actions: { fetch: this.fetch, // 其他action } })); } fetch() { this.fetchDataInsideClass(); } // 其他方法... }
内容的提问来源于stack exchange,提问作者Leos Literak
相关产品推荐
相关产品推荐

