【问题标题】:Cant resolve an issue with an infinite loop in a chat app无法解决聊天应用程序中的无限循环问题
【发布时间】:2020-01-22 11:24:26
【问题描述】:

我正在构建一个聊天应用程序...在初始化聊天页面时,我正在检查消息并将其存储在消息数组中

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

【问题讨论】:

  • ngInit 用于哪个文件?你的 app.component.ts?
  • 如果 ngInit 被多次调用,它的父组件会多次调用它并创建多个实例。问题不在于孩子

标签: angular typescript firebase google-cloud-firestore ionic4


【解决方案1】:

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

  1. 给messages.message分配新值时,它可能和json一样,但仍然所有对象都有新指针
  2. 因此 ngFor 认为它得到了不同对象的新数组
  3. 因此 ngFor 会销毁旧的 ion-item 并再次为“新”对象初始化它们,从而有效地在每个对象中调用 ngOnInit

这个问题的解决方案是将 trackBy 添加到 ngFor(在此处阅读更多信息 https://angular.io/api/common/NgForOf

其他可能的行为是您使用的某些方法返回无限 Observable,解决此问题的方法是在您的管道中添加带有 take(1) 或 filter(someFilterFunc) 的运算符(更多信息请阅读此处https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md

【讨论】:

  • 这不起作用...我知道我在这里做错了...我缺少一些东西。
  • 我做了两件事来解决这个问题...我用 trackBy 实现了你的建议,我还注意到在我的服务中我在文档上实现了 .OnSnapshot 而不是 .Get()。
  • 很高兴能帮到你
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
相关资源
最近更新 更多