本文详解 ng-bootstrap 模态框中数据传递的生命周期风险,对比 `componentinstance.data` 直接赋值、`@input()` + `ngonchanges`、服务注入三种方案,指出异步场景下的潜在竞态问题,并推荐基于 observable 的响应式数据流实践。
在使用 @ng-bootstrap/ng-bootstrap 构建模态框时,官方文档常推荐如下数据传递方式:
const modalRef = this.modalService.open(NgbdModalContent); modalRef.componentInstance.data = 'Hello World';
并在模态组件中通过 @Input() 接收:
@Component({
template: `{{ data }}`
})
export class NgbdModalContent {
@Input() data!: string;
ngOnInit(): void {
console.log(this.data); // ✅ 通常能打印出值,但不保证!
}
}
⚠️ 问题核心:这不是真正的 @Input() 绑定,而是手动属性赋值
modalService.open() 创建的是动态实例(非模板声明式渲染),因此 Angular 的变更检测机制不会触发 ngOnChanges —— 这正是你观察不到 ngOnChanges 被调用的原因。componentInstance.data = … 是对组件实例属性的直接写入,发生在组件已创建但尚未进入 Angular 生命周期钩子执行序列的间隙。若 data 依赖异步操作(如 HTTP 请求结果),而 ngOnInit 中立即使用该值,就存在典型的竞态条件(race condition):ngOnInit 可能在赋值前执行。
✅ 推荐方案:使用 injector + InjectionToken 实现类型安全、可订阅的数据传递
避免手动赋值带来的时序不确定性,应将数据作为依赖项,在组件初始化前就注入: