Angular向子组件传值前如何校验值非null/undefined避免ngOnInit取空值
问题原因
你当前写法的核心问题是*ngIf="list$"仅判断了Observable实例本身是否存在,没有校验异步流吐出的实际数据值:
list$在父组件ngOnInit执行后就被赋值为Observable实例,属于真值,会直接触发子组件创建- 此时
list$ | async还未收到store.select吐出的第一个有效值,传入子组件的data自然为null,子组件ngOnInit执行时拿到的就是空值
解决方案
根据业务场景选下面任意一种实现即可:
方案1:父组件层校验数据有效性,数据就绪后再渲染子组件
这是最贴合"传值前校验非null/undefined"需求的写法,利用*ngIf的as语法持有异步订阅的结果,只有数据有效时才实例化子组件,此时子组件ngOnInit中一定能拿到有效data。
修改父组件模板parent.component.html:
<!-- 仅当list$吐出的实际值非null/undefined时,才渲染子组件 --> <ng-container *ngIf="list$ | async as listData"> <child [data]="listData"></child> </ng-container>
如果业务中
0、空字符串、false这类假值是合法传入值,把判断条件改为严格校验非空即可:<ng-container *ngIf="(list$ | async) !== null && (list$ | async) !== undefined as listData"> <child [data]="listData"></child> </ng-container>注意这种写法会产生两次订阅,更推荐封装一个名为
notNull的自定义管道做非空校验,减少重复订阅。
方案2:子组件层监听输入变化,数据有效时再做处理
如果业务要求子组件需要提前渲染,不需要等数据到位再挂载,可以在子组件内监听输入值的变化,拦截空值后再执行预处理逻辑,两种实现方式二选一即可:
方式A:用Input属性setter拦截
修改child.component.ts:
import { Input } from '@angular/core'; private _data: any[]; @Input() set data(val: any[]) { // 拦截null/undefined空值 if (val == null) return; // 在这里写数据预处理逻辑 this._data = val; console.log('收到有效data', this._data); } get data() { return this._data; }
方式B:用ngOnChanges生命周期监听输入变更
import { Input, OnChanges, SimpleChanges } from '@angular/core'; @Input() data: any[]; ngOnChanges(changes: SimpleChanges): void { // 校验data输入存在且当前值非空 if (changes['data'] && changes['data'].currentValue != null) { // 在这里写数据预处理逻辑 console.log('收到有效data', this.data); } }
注意事项
- 不要对同一个Observable在模板中多次使用
async管道,会触发多次重复订阅,引发不必要的性能消耗和逻辑异常,优先用*ngIf as持有订阅结果复用 - 如果使用ngrx/store的select,要确认对应selector初始值是否设置正确,避免selector默认返回null导致流迟迟不吐出有效值
内容的提问来源于stack exchange,提问作者Johnny
相关产品推荐
相关产品推荐

