Spartacus从4.1.0升级到5.0.0后调用getSelectedPaymentTypeState()出现栈溢出错误
getSelectedPaymentTypeState()栈溢出问题解决 升级Spartacus从4.1.0到5.0.0后,支付类型页面调用getSelectedPaymentTypeState()出现如下栈溢出错误:
node_modules_spartacus_checkout_fesm2020_spartacus-checkout-base_mjs.js:2 RangeError: Maximum call stack size exceeded at Subscriber._error (Subscriber.js:75:26) at Subscriber.error (Subscriber.js:55:18) at MapSubscriber._error (Subscriber.js:75:26) at MapSubscriber.error (Subscriber.js:55:18) at FilterSubscriber._error (Subscriber.js:75:26) at FilterSubscriber.error (Subscriber.js:55:18) at SwitchMapSubscriber.notifyError (innerSubscribe.js:45:26) at SimpleInnerSubscriber._error (innerSubscribe.js:13:21) at SimpleInnerSubscriber.error (Subscriber.js:55:18) at SwitchMapSubscriber.notifyError (innerSubscribe.js:45:26)
以下是排查和解决方向:
检查状态选择器的使用方式
Spartacus 5.x对状态管理API有破坏性变更,确认调用getSelectedPaymentTypeState()时是否正确配合RxJS操作符。正确用法是通过store.select()获取Observable,而非直接调用后重复订阅:// 正确示例 import { Store } from '@ngrx/store'; import { getSelectedPaymentTypeState } from '@spartacus/checkout/base/root'; constructor(private store: Store) {} ngOnInit() { this.selectedPaymentType$ = this.store.select(getSelectedPaymentTypeState); }模板中使用时务必搭配
async管道,避免手动订阅引发的内存泄漏或循环触发:<div *ngIf="selectedPaymentType$ | async as paymentType"> <!-- 渲染支付类型内容 --> </div>排查循环订阅/状态更新逻辑
检查组件或服务中是否存在「订阅getSelectedPaymentTypeState()结果后,又触发支付类型变更action」的逻辑,这种情况会形成无限循环直接导致栈溢出。比如:// 错误示例:触发循环 this.store.select(getSelectedPaymentTypeState).subscribe(paymentType => { if (!paymentType) { this.store.dispatch(setPaymentType({ type: 'DEFAULT' })); } });这类逻辑需添加精准条件判断,或用
distinctUntilChanged()过滤重复值:this.store.select(getSelectedPaymentTypeState) .pipe(distinctUntilChanged()) .subscribe(paymentType => { // 处理逻辑 });检查自定义扩展的兼容性
如果项目有自定义支付类型相关状态或选择器,确认是否适配了Spartacus 5.x的状态树结构。4.x到5.x的checkout状态路径可能变化,自定义选择器若沿用旧路径,会导致无法正确获取状态,进而引发RxJS流的错误循环。排查循环依赖
检查支付相关自定义服务是否存在循环依赖(如A服务依赖B服务,B服务又依赖A服务),这种情况下服务初始化会触发无限调用,最终导致栈溢出。可通过Angular依赖注入调试工具排查。调试RxJS流
在调用链路中添加tap()操作符打印日志,跟踪流的触发次数和数据变化,定位循环触发源头:this.store.select(getSelectedPaymentTypeState) .pipe(tap(data => console.log('Payment type state changed:', data))) .subscribe();
内容的提问来源于stack exchange,提问作者Saravanan

