【问题标题】:Weird behavior while using Subjects/event emitters in services for cross component communication in angular?在服务中使用主题/事件发射器以角度进行跨组件通信时的奇怪行为?
【发布时间】:2020-05-29 10:30:26
【问题描述】:

我想了解可观察性、主题和行为主题的工作方式(阅读了很多文章,观看了很多视频,但我仍然不清楚,因为我未能解释这种行为)所以我创建了这个简单的示例并得到了意想不到的行为。 我有两个组件,一个父组件和一个子组件

父组件显示具有照片名称的列表,并带有显示详细信息的按钮。单击此按钮时,它将带我们进入我希望在其中显示单张照片以及详细信息的子组件。所以,这就是想法。

我使用了一项服务,我有一个主题。现在,每当单击父组件中的按钮时,我都会从主题中发出一个值。我想在我的子组件中捕获这个值,所以我订阅了它。

有一种奇怪的行为—— 对于第一次单击,我在我的子组件中看不到任何数据。 第二次单击子组件中的单个值。 第三次单击子组件中的两个值, 等等……

这是我的组件--

parent.component.ts

export class ParentComponent implements OnInit {
  photoList = [
    {
      albumId: 1,
      id: 1,
      title: "accusamus beatae ad facilis cum similique qui sunt",
      url: "https://via.placeholder.com/600/92c952",
      thumbnailUrl: "https://via.placeholder.com/150/92c952",
    },
    {
      albumId: 1,
      id: 2,
      title: "reprehenderit est deserunt velit ipsam",
      url: "https://via.placeholder.com/600/771796",
      thumbnailUrl: "https://via.placeholder.com/150/771796",
    },
    {
      albumId: 1,
      id: 3,
      title: "officia porro iure quia iusto qui ipsa ut modi",
      url: "https://via.placeholder.com/600/24f355",
      thumbnailUrl: "https://via.placeholder.com/150/24f355",
    },
  ];
  constructor(private _talkService: TalkService, private router: Router) {}

  ngOnInit() {}

  displayName(id, url, thumbnailUrl) {
    console.log({ id, url, thumbnailUrl });

    //this._talkService.talk.emit({ url, thumbnailUrl });
    this._talkService.talk.next({ id, url, thumbnailUrl });
    this.router.navigate(["/photo"]);
  }
}

child.component.ts

export class ChildComponent implements OnInit {
  constructor(private _talkService: TalkService) {}

  ngOnInit() {
    console.log("child component created");
    this._talkService.talk.subscribe((data) => {
      console.log(data);
    });
  }
}

talk.service.ts

@Injectable({
  providedIn: "root",
})
export class TalkService {
  // talk = new EventEmitter();
  talk = new Subject();
  constructor() {}
}

输出控制台日志

这三个我都用过--

事件发射器-->与描述的行为相同 主题-->与描述的行为相同 行为主题--> 我也得到了第一个值(因为它有助于我们获取先前发出的值,我理解那部分)。也欢迎在这里详细解释。

我希望每次点击都有一个值,但事实并非如此。有人可以解释一下我的行为。它必须是可观察的工作方式,我无法得到它。

这是我的 github 仓库的链接--

source code github

【问题讨论】:

  • 你能提供一个stackblitz吗?
  • 我不知道该怎么做。如果有帮助的话,我可以分享 git hub repo 链接...
  • google angular stackblitz,打开第一个链接,点击 fork,做你的代码,保存你的代码,点击分享,从分享窗口发送第一个链接。
  • 它不工作,它说无法导入我的组件和 src 包 nt 找到..我已经分享了我的 gitub repo 的链接,你可以分叉它并尝试它的一小段代码。谢谢.....

标签: angular observable behaviorsubject subject


【解决方案1】:

听起来像是典型的内存泄漏。每次您订阅talkService.talk 时,您都在创建一个只有在取消订阅后才会被清除的订阅。因此,即使当您返回父组件时,子组件似乎已被销毁,但订阅仍然存在,并且每次 talk 主题发出新值时都会执行控制台日志。当子组件被销毁时,您应该取消订阅。确保取消订阅的一种简单方法是在 html 模板中使用 async 管道。

child.component.ts

export class ChildComponent implements OnInit {
  data$: Observable<any> = this.talkService.talk;

  constructor(private talkService: TalkService) {}
}

child.component.html

<pre>{{ data$ | async }}</pre>

此外,您可以切换回使用BehaviorSubject,因为在父组件发出值后,子组件将订阅talk

【讨论】:

  • 有道理,但我想知道,一旦我订阅了一个事件并使用数据,当我在同一个按钮上订阅另一个点击事件时,数据如何仍然可用,了解我在尝试什么怎么说?就像它是如何工作的一样,主题总是存储所有事件值?
  • 我尝试使用你提供的代码,异步管道的东西,它没有工作,我得到了同样的行为。它对你有用吗?
  • 主题并不真正“存储”值,它们发出值。它们是一种您可以订阅的可观察对象,并且您可以使用这些订阅处理从主题发出的值。是的,它对我有用,您可能没有删除子组件中的订阅。检查这个堆栈闪电战。 stackblitz.com/edit/angular-vrcgkp
  • 你能不能再分享一下stackblitz链接,上面的链接已经失效了
  • 如果您针对您的问题创建了一个堆栈闪电战,这样您就可以管理和拥有它,这可能会更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-18
  • 2022-11-30
  • 1970-01-01
  • 1970-01-01
  • 2017-04-30
相关资源
最近更新 更多