如何解决打字稿:订阅数据消失了 模拟错误解决方案:使用RxJS ReplaySubject
[投票赞成关闭的人:我不想将所有内容放到ngOnit
中-因为我告诉你:我需要在许多函数中重用API响应和模型数组,因此我需要写点东西这样我就可以重复使用
您知道,我实际上可以解决所有问题,只需调用subscribe中的所有内容或在每个函数中一次又一次地订阅即可。
我已经尝试过其他SO问题,其中大多数都放在ngOnIt
中。我只想在那儿调用必要的函数,所以请不要弄乱那个地方
请帮助我编写一个函数,以便我可以重用我的API响应或我可以重用由API响应this.menu = data;
初始化的模型
我想从我的API响应中打印菜单。
此外,我需要在多个函数中多次使用响应,但是当我离开subscribe
块时,我会得到空值
这是我的代码:
import { Component,OnInit } from '@angular/core';
// import { LoginModel } from "../../models/login/login-model";
import { MenuModel } from "../../models/menu/menu-model";
import { SubmenuModel } from "../../models/submenu/submenu-model";
// import { AccessModel } from "../../models/access/access-model";
import { MenuService } from "../../services/menu/menu.service";
import { SubmenuService } from "../../services/submenu/submenu.service";
@Component({
selector: 'app-admin-access',templateUrl: './admin-access.component.html',styleUrls: ['./admin-access.component.css']
})
export class AdminAccessComponent implements OnInit {
menu: MenuModel[] = null;
submenu: SubmenuModel[] = null;
constructor(private menuService: MenuService,private submenuSerive: SubmenuService) { }
ngOnInit(): void {
this.getMenu();
this.printMenu();
}
getMenu() {
this.menuService.GetAllMenu().subscribe((data: MenuModel[]) => {
this.menu = data;
console.log("first use : ");
console.log(data);
console.log("second use : ");
console.log(this.menu);
})
}
printMenu(){
console.log("third use : ");
console.log(this.menu);
}
}
此处输出:
从printMenu()
函数中看到,我所有的响应都为空。但为什么?我确实已经订阅并保存了值。
那么我该如何从API响应中永久保存一个值?
解决方法
(我发布此解决方案的唯一原因是:将来,像我这样的初学者不必每天[隐喻地]撞墙,也不必为发现可观的损失而烦恼超过2周的项目发现时间
我也想与您分享2件事-仅当您是初学者时,您才能理解它[不要对此发表评论-我要求您-我有权对我的问题表达自己的看法-请不要审判我]
1。优点:
大多数人都不明白我的意思。我相信他们确实知道这个答案,但是似乎他们不明白我想要什么,只有其中一些人试图给我建议(我对此表示感谢),但是其中大多数人并不在意理解或不理解甚至不愿问任何事情来理解。所以初学者:您只需要找到一个幸运的日子,当人们真正理解您的要求
2。文件
开枪-一个很大的笑话(对于初学者)
很长一段时间-[就我而言-有角度的]文档不会帮助您,除非您没有一定程度的编程知识,就像我以前从未使用过observable
或ngOnit
一样,但是有人指出我是如何工作的。仍然我不了解observable
或ngOnit
的大部分内容,但现在我对它了解4到5件事。
所以我对初学者的建议:留下文档(如果需要或如果您觉得难以理解)并转到youtube教程)
问题原因:
还记得我的ngOnIt吗?
ngOnInit(): void {
//line 1
this.getMenu();
//line 2
this.printMenu();
}
ngOnIt
不会逐行执行,如果这样做,我实际上可以第三次更正值而不是null值(请参见屏幕快照中的值)。 ngOnit
一次执行所有操作(不是逐行执行)。因此,尽管似乎第2行将在第1行之后执行,但不是,因为我们不在正常函数中,所以我们在ngOnit
解决方案
当我找到解决方案时,我很惊讶(很高兴知道)实际上没有编码错误,我只需要在初始化{{之后,在printMenu()
之外调用ngOnit
1}}在getMenu()
那我该怎么打外面的电话?我需要活动
如何触发事件?最简单的方法是使用点击事件创建按钮
所以这是我的 .html :
ngOnit
.ts :
<button (click)="this.printMenu()"> Lets test it </button>
几乎没有变化,我只需要从import { MenuService } from "../../services/menu/menu.service";
import { SubmenuService } from "../../services/submenu/submenu.service";
@Component({
selector: 'app-admin-access',templateUrl: './admin-access.component.html',styleUrls: ['./admin-access.component.css']
})
export class AdminAccessComponent implements OnInit {
menu: MenuModel[] = null;
submenu: SubmenuModel[] = null;
constructor(private menuService: MenuService,private submenuSerive: SubmenuService) { }
ngOnInit(): void {
this.getMenu();
}
getMenu() {
this.menuService.GetAllMenu().subscribe((data: MenuModel[]) => {
this.menu = data;
//console.log("first use : ");
//console.log(data);
//console.log("second use : ");
//console.log(this.menu);
})
}
printMenu(){
console.log("third use : ");
console.log(this.menu);
}
}
中删除printmenu
,然后通过一个事件(按钮或您喜欢的其他任何东西)调用它即可。
[我也在代码中注释了第一次使用和第二次使用]
,从您的答案看来,当您在订阅之外打印时,您似乎仍然无法理解为什么该变量未定义。 this.menu
是异步分配的。如果您花时间阅读我在评论中所附的this答案,您将会对此有所了解。
基本上,在printMenu()
函数中打印变量时,变量未分配任何值。您的答案仍然是错误的。它假定在按下按钮时定义了变量,但事实并非如此。 您永远不能假定已经定义了异步变量。
模拟错误
您可以通过使用RxJS delay
运算符人为地引起延迟来模拟此错误。我引起了10秒的延迟。因此,如果您在应用启动后10秒钟内按下按钮,则printMenu()
仍会打印null
。在现实情况下,GetAllMenu()
函数实际上可能会导致这种延迟,因为前端无法控制其响应时间。
import { delay } from "rxjs/operators";
@Component({
selector: 'app-admin-access',styleUrls: ['./admin-access.component.css']
})
export class AdminAccessComponent implements OnInit {
menu: MenuModel[] = null;
submenu: SubmenuModel[] = null;
constructor(private menuService: MenuService,private submenuSerive: SubmenuService) { }
ngOnInit(): void {
this.getMenu();
}
getMenu() {
this.menuService.GetAllMenu().pipe(
delay(10000) // <-- simulate delay of 10 seconds
).subscribe((data: MenuModel[]) => {
this.menu = data;
});
}
printMenu() {
console.log(this.menu); // <-- would still print `null` if called within 10 seconds
}
}
正确的解决方案是使所有后续语句也异步。
解决方案:使用RxJS ReplaySubject
ReplaySubject
是一个多播的可观察对象,可保存/缓冲最后发出的n
值,并在订阅后立即发出。在这种情况下,缓冲区大小为1应该足够了。您可以将源通知从GetAllMenu()
推送到其他受抚养者可以订阅的可观察对象。
import { ReplaySubject } from "rxjs";
@Component({
selector: 'app-admin-access',styleUrls: ['./admin-access.component.css']
})
export class AdminAccessComponent implements OnInit {
menu$: ReplaySubject<MenuModel[]> = new ReplaySubject<MenuModel[]>(1);
submenu: SubmenuModel[] = null;
constructor(private menuService: MenuService,private submenuSerive: SubmenuService) { }
ngOnInit(): void {
this.getMenu();
this.printMenu();
}
getMenu() {
this.menuService.GetAllMenu().subscribe((data: MenuModel[]) => {
this.menu$.next(data); // <-- push value to `ReplaySubject` observable
console.log("first use : ");
console.log(data);
});
}
printMenu(){
this.menu$.subscribe((data: MenuModel[]) => { // <-- subscribe to the `ReplaySubject` observable
console.log("third use : ");
console.log(data);
});
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。