我想在 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 的结果的主要内容,如果未能解决你的问题,请参考以下文章

Xamarin形式 - 背景中的第二个图像

我怎么做svn开关结帐的第二个副本

选择 Pandas DataFrame 的第二个 MultiIndex 级别作为索引器

取一个 TD,并将其插入到父 TR 中的第二个 TD 之后

如何在列表jquery中的第二个“ li”之后加上前缀

如何访问数据表页脚的第二行