使用ASP.NET Core+Angular5+SignalR时,*ngFor DOM回调后不刷新问题
解决Angular 5 + SignalR回调后*ngFor DOM不刷新的问题
这个坑我之前踩过!你遇到的问题本质是SignalR的回调函数运行在Angular的变更检测上下文之外,所以哪怕你更新了messages数组,Angular也没察觉到,自然不会触发DOM刷新。下面给你几个实用的解决办法:
方法1:用NgZone把回调代码包起来
NgZone是Angular用来管理变更检测的核心工具,把回调逻辑放到ngZone.run()里,就能让代码回到Angular的变更检测范围内:
- 先在组件里注入
NgZone:
import { Component, NgZone } from '@angular/core'; @Component({ // 组件元数据 }) export class ChatComponent { constructor(private ngZone: NgZone) {} }
- 修改SignalR的回调代码:
this.hubConnection.on('sendToAll', (nickname: string, message: string) => { this.ngZone.run(() => { this.messages.push(new Message(nickname, message)); }); });
方法2:手动触发变更检测
如果不想用NgZone,也可以直接调用变更检测器的detectChanges()方法,强制Angular刷新DOM:
- 注入
ChangeDetectorRef:
import { Component, ChangeDetectorRef } from '@angular/core'; @Component({ // 组件元数据 }) export class ChatComponent { constructor(private cdr: ChangeDetectorRef) {} }
- 在更新数组后手动触发检测:
this.hubConnection.on('sendToAll', (nickname: string, message: string) => { this.messages.push(new Message(nickname, message)); this.cdr.detectChanges(); // 强制刷新DOM });
方法3:用Observable管理数据(更优雅的方式)
推荐用RxJS的BehaviorSubject来管理messages数组,因为Angular会自动监听Observable的变化,配合async管道使用,完全不用手动处理变更检测:
- 定义BehaviorSubject并初始化:
import { Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Component({ // 组件元数据 }) export class ChatComponent { // 用BehaviorSubject保存消息数组,初始为空数组 private messagesSubject = new BehaviorSubject<Message[]>([]); // 对外暴露Observable供模板使用 messages$ = this.messagesSubject.asObservable(); // ...其他代码 }
- 在SignalR回调里更新Subject的值:
this.hubConnection.on('sendToAll', (nickname: string, message: string) => { // 获取当前的消息数组 const currentMessages = this.messagesSubject.value; // 用新数组替换旧数组(注意要创建新数组,不能直接push,因为BehaviorSubject只监听引用变化) this.messagesSubject.next([...currentMessages, new Message(nickname, message)]); });
- 模板里用
async管道绑定:
<div *ngFor="let msg of messages$ | async"> {{ msg.nickname }}: {{ msg.message }} </div>
为什么会出现这个问题?
简单说,Angular的变更检测默认只监听Angular内部触发的事件(比如点击事件、HTTP请求完成、定时器等),但SignalR的回调是由浏览器的WebSocket事件触发的,不在Angular的默认监测范围内,所以数组更新了Angular也不知道,DOM就不会同步更新。
内容的提问来源于stack exchange,提问作者Atlasmaybe
相关产品推荐
相关产品推荐

