无法解决聊天应用程序中无限循环的问题
Cant resolve an issue with an infinite loop in a chat app
我正在构建一个聊天应用程序...在初始化聊天页面时我正在检查消息并将其存储在消息数组中
ngOnInit() {
this.messageService.getMessages().doc(`${this.sortItineraries[0] + '-' + this.sortItineraries[1]}`)
.onSnapshot((doc) => {
console.log('init message.page in snapshot', doc.data().message);
this.messages = [];
this.messages = doc.data();
console.log('init message.page variable', this.messages);
});
}
我用下面的代码发送消息时出现死循环
getMessages() {
return this.allMessages;
}
getAllMessages() {
return this.allMessages;
}
async createMessage(itineraries) {
console.log('createMessage');
const docRef = await firebase.firestore().doc(`messages/${itineraries}`).set({
message: []
});
}
async sendMessage(id, content, userId) {
this.allMessages.doc(`${id}`)
.onSnapshot((doc) => {
if (doc.exists) {
console.log('sendmessage doc exists');
this.send(id, content, userId);
} else {
this.createMessage(id)
.then(() => {
console.log('sendmessage !doc exists');
this.send(id, content, userId);
});
}
});
}
async send(id, content, userId) {
console.log('send');
const uid = this.loggedInUser.uid;
const ref = this.afs.collection('messages').doc(id);
return ref.update({
message: firebase.firestore.FieldValue.arrayUnion({
content,
createdAt: Date.now(),
userId
})
});
}
<ion-content>
<ion-list lines="none">
<ion-item *ngFor="let message of messages.message">
<div size="9" *ngIf="myItinerary.userId !== message.userId" class="message other-user">
<span>{{message.content}}</span>
<div class="time" text-right><br>
{{message.createdAt | date: 'short'}}</div>
</div>
<div offset="3" size="9" *ngIf="myItinerary.userId === message.userId" class="message me" slot="end">
<span>{{message.content}}</span>
<div class="time" text-right><br>
{{message.createdAt | date: 'short'}}</div>
</div>
</ion-item>
</ion-list>
</ion-content>
<ion-footer>
<ion-toolbar light="light">
<ion-row align-items-center no-padding>
<ion-col size="8">
<textarea autosize maxRows="3" [(ngModel)]="newMsg" class="message-input"></textarea>
</ion-col>
<ion-col size="3">
<ion-button expand="block" fill="clear" color="primary" [disabled]="newMsg === ''" class="msg-btn"
(click)="sendMessage()">
<ion-icon name="ios-send" slot="icon-only"></ion-icon>
</ion-button>
</ion-col>
</ion-row>
</ion-toolbar>
</ion-footer>
屏幕截图显示了控制台日志,其中它在创建消息并将消息发送到 firebase 后端的服务与 init 之间循环。它一直循环,直到我退出应用程序并删除 firebase 中的消息。
我在服务中所做的是检查文档是否已创建
async sendMessage(id, content, userId) {
this.allMessages.doc(`${id}`)
.onSnapshot((doc) => {
if (doc.exists) {
console.log('sendmessage doc exists');
this.send(id, content, userId);
} else {
this.createMessage(id)
.then(() => {
console.log('sendmessage !doc exists');
this.send(id, content, userId);
});
}
});
}
如果它不存在,那么我会在将消息推送到 firebase 中的消息数组之前创建它
async createMessage(itineraries) {
console.log('createMessage');
const docRef = await firebase.firestore().doc(`messages/${itineraries}`).set({
message: []
});
}
async send(id, content, userId) {
console.log('send');
const uid = this.loggedInUser.uid;
const ref = this.afs.collection('messages').doc(id);
return ref.update({
message: firebase.firestore.FieldValue.arrayUnion({
content,
createdAt: Date.now(),
userId
})
});
}
但是在完成之后它会继续调用 init 函数获取所有消息并将其存储在消息中 属性
<ion-list lines="none">
<ion-item *ngFor="let message of messages.message">
我认为您的问题来自以下行为之一:
- 当新值赋给messages.message时,它可能等于json,但仍然所有对象都有新指针
- 因此 ngFor 认为它得到了不同对象的新数组
- 因此 ngFor 会销毁旧的 ion-item 并为 'new' 个对象再次初始化它们,有效地在每个对象中调用 ngOnInit
此问题的解决方案是将 trackBy 添加到 ngFor(在此处阅读更多内容 https://angular.io/api/common/NgForOf)
其他可能的行为是您使用的某些方法 return infinite Observable,解决此问题的方法是将带有 take(1) 或 filter(someFilterFunc) 的运算符添加到您的管道中(有关更多信息,请阅读此处https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md)
我正在构建一个聊天应用程序...在初始化聊天页面时我正在检查消息并将其存储在消息数组中
ngOnInit() {
this.messageService.getMessages().doc(`${this.sortItineraries[0] + '-' + this.sortItineraries[1]}`)
.onSnapshot((doc) => {
console.log('init message.page in snapshot', doc.data().message);
this.messages = [];
this.messages = doc.data();
console.log('init message.page variable', this.messages);
});
}
我用下面的代码发送消息时出现死循环
getMessages() {
return this.allMessages;
}
getAllMessages() {
return this.allMessages;
}
async createMessage(itineraries) {
console.log('createMessage');
const docRef = await firebase.firestore().doc(`messages/${itineraries}`).set({
message: []
});
}
async sendMessage(id, content, userId) {
this.allMessages.doc(`${id}`)
.onSnapshot((doc) => {
if (doc.exists) {
console.log('sendmessage doc exists');
this.send(id, content, userId);
} else {
this.createMessage(id)
.then(() => {
console.log('sendmessage !doc exists');
this.send(id, content, userId);
});
}
});
}
async send(id, content, userId) {
console.log('send');
const uid = this.loggedInUser.uid;
const ref = this.afs.collection('messages').doc(id);
return ref.update({
message: firebase.firestore.FieldValue.arrayUnion({
content,
createdAt: Date.now(),
userId
})
});
}
<ion-content>
<ion-list lines="none">
<ion-item *ngFor="let message of messages.message">
<div size="9" *ngIf="myItinerary.userId !== message.userId" class="message other-user">
<span>{{message.content}}</span>
<div class="time" text-right><br>
{{message.createdAt | date: 'short'}}</div>
</div>
<div offset="3" size="9" *ngIf="myItinerary.userId === message.userId" class="message me" slot="end">
<span>{{message.content}}</span>
<div class="time" text-right><br>
{{message.createdAt | date: 'short'}}</div>
</div>
</ion-item>
</ion-list>
</ion-content>
<ion-footer>
<ion-toolbar light="light">
<ion-row align-items-center no-padding>
<ion-col size="8">
<textarea autosize maxRows="3" [(ngModel)]="newMsg" class="message-input"></textarea>
</ion-col>
<ion-col size="3">
<ion-button expand="block" fill="clear" color="primary" [disabled]="newMsg === ''" class="msg-btn"
(click)="sendMessage()">
<ion-icon name="ios-send" slot="icon-only"></ion-icon>
</ion-button>
</ion-col>
</ion-row>
</ion-toolbar>
</ion-footer>
屏幕截图显示了控制台日志,其中它在创建消息并将消息发送到 firebase 后端的服务与 init 之间循环。它一直循环,直到我退出应用程序并删除 firebase 中的消息。
我在服务中所做的是检查文档是否已创建
async sendMessage(id, content, userId) {
this.allMessages.doc(`${id}`)
.onSnapshot((doc) => {
if (doc.exists) {
console.log('sendmessage doc exists');
this.send(id, content, userId);
} else {
this.createMessage(id)
.then(() => {
console.log('sendmessage !doc exists');
this.send(id, content, userId);
});
}
});
}
如果它不存在,那么我会在将消息推送到 firebase 中的消息数组之前创建它
async createMessage(itineraries) {
console.log('createMessage');
const docRef = await firebase.firestore().doc(`messages/${itineraries}`).set({
message: []
});
}
async send(id, content, userId) {
console.log('send');
const uid = this.loggedInUser.uid;
const ref = this.afs.collection('messages').doc(id);
return ref.update({
message: firebase.firestore.FieldValue.arrayUnion({
content,
createdAt: Date.now(),
userId
})
});
}
但是在完成之后它会继续调用 init 函数获取所有消息并将其存储在消息中 属性
<ion-list lines="none">
<ion-item *ngFor="let message of messages.message">
我认为您的问题来自以下行为之一:
- 当新值赋给messages.message时,它可能等于json,但仍然所有对象都有新指针
- 因此 ngFor 认为它得到了不同对象的新数组
- 因此 ngFor 会销毁旧的 ion-item 并为 'new' 个对象再次初始化它们,有效地在每个对象中调用 ngOnInit
此问题的解决方案是将 trackBy 添加到 ngFor(在此处阅读更多内容 https://angular.io/api/common/NgForOf)
其他可能的行为是您使用的某些方法 return infinite Observable,解决此问题的方法是将带有 take(1) 或 filter(someFilterFunc) 的运算符添加到您的管道中(有关更多信息,请阅读此处https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md)