无法解决聊天应用程序中无限循环的问题

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">

我认为您的问题来自以下行为之一:

  1. 当新值赋给messages.message时,它可能等于json,但仍然所有对象都有新指针
  2. 因此 ngFor 认为它得到了不同对象的新数组
  3. 因此 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)