Angular RxJS订阅报错:Cannot read properties of undefined (reading 'filter')
解决RxJS Observable中"Cannot read properties of undefined (reading 'filter')"错误
在Angular组件中使用RxJS Observable时出现TypeError: Cannot read properties of undefined (reading 'filter'),错误发生在订阅userService.users$并尝试过滤用户列表排除已登录用户的操作中。
问题根源
- BehaviorSubject初始值不合理:UserService中的
_users$和_loggedUser$初始值设为undefined,但getter直接断言为非空类型,导致组件订阅时可能收到undefined,调用数组方法filter时触发错误。 - 异步流未同步:
users$和loggedUser$是独立异步流,组件分别订阅时,可能users$先返回数据但loggedUser还未赋值,此时访问this.loggedUser.id会引发错误。 - 未处理空值边界:组件中未对
users是否为有效数组做判断,直接调用filter方法。
修复方案
1. 修正UserService的初始值与类型
将BehaviorSubject的初始值改为合理默认值,移除不安全的类型断言:
// user.service.ts export class UserService { // 初始化为空数组,避免undefined private _users$: BehaviorSubject<User[]> = new BehaviorSubject<User[]>([]); // 初始化为null,明确表示未加载状态 private _loggedUser$: BehaviorSubject<User | null> = new BehaviorSubject<User | null>(null); constructor(private userHttpService: UserHttpService, private router: Router, private dtoMapperService: DtoMapperService, private matSnackBar: MatSnackBar,) { this.fetchUsers(); this.fetchLoggedUser(); } // 直接返回正确类型,无需强制断言 public get users$(): Observable<User[]> { return this._users$.asObservable(); } public get users(): User[] { return this._users$.getValue(); } public get loggedUser$(): Observable<User | null> { return this._loggedUser$.asObservable(); } public get loggedUser(): User | null { return this._loggedUser$.getValue(); } // 其余方法保持不变 }
2. 合并RxJS流,同步处理数据
使用combineLatest合并两个异步流,确保已登录用户数据就绪后再过滤用户列表:
// user-list.component.ts import { combineLatest, Subscription } from 'rxjs'; import { filter, map } from 'rxjs/operators'; export class UserListComponent implements OnInit, OnDestroy { protected readonly Object = Object; groupedAndSortedUsers!: { [key: string]: User[] }; private subscription!: Subscription; constructor(public userService: UserService) {} ngOnInit() { this.subscription = combineLatest([ this.userService.users$, this.userService.loggedUser$ ]).pipe( // 过滤掉已登录用户未加载的情况 filter(([_, loggedUser]) => loggedUser !== null), // 映射为排除已登录用户后的列表 map(([users, loggedUser]) => users.filter(user => user.id !== loggedUser!.id)) ).subscribe(filteredUsers => { this.groupedAndSortedUsers = this.userService.groupAndSortUsers(filteredUsers); }); } ngOnDestroy() { this.subscription.unsubscribe(); } }
3. 模板中添加空值防护
在HTML模板中增加空值判断,避免数据未初始化时渲染出错:
<!-- user-list.component.html --> <div class="user-list-box"> <mat-list-item role="listitem">ME</mat-list-item> <mat-divider></mat-divider> <!-- 已登录用户未加载时不渲染 --> @if (userService.loggedUser) { <app-user [user]="userService.loggedUser"></app-user> } <mat-list role="list"> <!-- 分组用户数据未初始化时不渲染 --> @if (groupedAndSortedUsers) { @for (letter of Object.keys(groupedAndSortedUsers); track letter) { <mat-list-item role="listitem">{{ letter }}</mat-list-item> <mat-divider></mat-divider> @for (user of groupedAndSortedUsers[letter]; track user.id) { <app-user [user]="user"></app-user> } } } </mat-list> </div>
内容的提问来源于stack exchange,提问作者coder
相关产品推荐
相关产品推荐

