我想在 ngOnInit() 的第二个方法中使用 .subscribe 的结果
Posted
技术标签:
【中文标题】我想在 ngOnInit() 的第二个方法中使用 .subscribe 的结果【英文标题】:I want to use the results of .subscribe in a method inside a second method in ngOnInit() 我想在 ngOnInit() 的第二个方法中使用 .subscribe 的结果 【发布时间】:2019-11-26 14:38:24 【问题描述】:我有一个使用服务获取书籍列表的方法,我需要第二种方法,它使用书籍列表通过 id 过滤来获取一本书。这两个方法在同一个组件的“ngOnInit”中调用。我得到的是第二种方法在得到结果之前使用书籍列表。
我通过在 .subscribe 的结果中调用第一个方法中的第二个方法,然后在 ngOnInit 中仅调用第一个方法来解决此问题。我没有找到非常令人满意的解决方案,我想要一种更通用和更有条理的方式......
export class BookComponent implements OnInit
public books: Book[];
public book: Book;
public id;
public sub;
constructor(private activatedRoute: ActivatedRoute, private router: Router, private bookService: BookService)
getBooks()
this.bookService.getBooks().subscribe(
result =>
this.books = result;
);
findById()
this.sub = this.activatedRoute.paramMap.subscribe(params =>
console.log(params);
this.id = params.get('id');
this.book = this.books.find(a => a.id == this.id);
);
ngOnInit()
this.getbooks();
this.findById();
这是我得到的错误:
ERROR TypeError: Cannot read property 'find' of undefined
【问题讨论】:
【参考方案1】:试试这个
findById()
this.sub = this.activatedRoute.paramMap.subscribe(params =>
console.log(params);
this.id = params.get('id');
this.book = this.books.find(a => a.id == this.id);
);
ngOnInit()
this.books = [];
this.getbooks();
this.findById();
【讨论】:
这可以防止未定义的错误,但对于解决未定义的根本问题(或现在[]
)无济于事。
感谢这个想法,它确实有效,但仅在第二次尝试时,第一次尝试当我第一次路由到一本书并分配一个特定的“id”时它不起作用......【参考方案2】:
发生这种情况是因为图书未初始化。由于您同时运行两个异步函数,因此无法保证在您调用findById()
之前books
的内容已由getBooks()
初始化。
你可以通过将findById()
的调用放在getBooks()
的调用中来避免这个问题。这种会导致订阅地狱(多个嵌套订阅),但这可以通过使用 rxjs 来清除。
在下面相应地重新排列了您的原始代码。
export class BookComponent implements OnInit
public books: Book[];
public book: Book;
public id;
public sub;
constructor(private activatedRoute: ActivatedRoute, private router: Router, private bookService: BookService)
ngOnInit()
this.getbooks();
getBooks()
this.bookService.getBooks().subscribe(
result =>
this.books = result;
this.findById()
);
findById()
this.sub = this.activatedRoute.paramMap.subscribe(params =>
console.log(params);
this.id = params.get('id');
this.book = this.books.find(a => a.id == this.id);
);
【讨论】:
感谢您的回复,这实际上是我描述的解决方案,我不喜欢的解决方案,因为这样 getBooks() 不仅可以获取书籍,还可以通过 id 进行过滤......那就是为什么我想要一种更有条理的方式。 您可以使用 rxjs 来执行此操作,但它的工作方式与标准 TS 不同。请参阅this question/answer 了解更多信息。我会说可能从参数中获取 id,然后在调用 http 时使用它【参考方案3】:您的直觉是正确的,您不应该尝试在 subscribes 中调用 subscribes...您应该使用更高阶的 observables 来实现这一目标,并确保在需要的地方获得所有 observable 数据。在这种情况下,您想使用 combineLatest:
ngOnInit()
this.sub = combineLatest(this.bookService.getBooks(), this.activatedRoute.paramMap)
.subscribe(([books, params]) =>
this.books = books;
this.id = params.get('id');
this.book = this.books.find(a => a.id == this.id);
);
现在订阅回调将在每次任何可观察流发出时运行,但只有一次两者都至少发出一次。其余的都不需要。在这种情况下,我假设 getBooks() 只会发出一次,但如果用户导航到不同的图书 ID,paramMap 可能会再次发出。
【讨论】:
谢谢你解释清楚的回复,我喜欢你的想法,但也想到了一些代码行会如何重复,因为我真正想要的是一个单独的方法,让我得到书,而不是重新- 使用结果而不重新获取它们,可能/可能通过其他方法,如 findById ...以上是关于我想在 ngOnInit() 的第二个方法中使用 .subscribe 的结果的主要内容,如果未能解决你的问题,请参考以下文章