对于第5角的rxjs,我还是有点陌生,很难提出我的问题。不过,我还是希望得到一些建议。
我常常以同样的设置结束:
现在,在通过可观测数据接收数据时,我有两个选择:
( a)订阅可观察到的数据一次,再订阅一次以获取更新
( b)订阅可观察到的内容,并在数据更改时始终获得更新
( a)直截了当,但对于b)我经常遇到麻烦,不知道这是否是使用可观察的正确方法。
一个问题是,在某些情况下,取消订阅变得非常重要,而缺少取消订阅会导致在每次更新可观察到的内容时执行严重的垃圾。
另一方面,使用选项a),当另一个组件正在更新底层数据时,我可能会错过一个组件中的一些更新。
有什么最佳做法来避免所有这些陷阱吗?
发布于 2018-03-15 11:12:40
听起来,您想要弄清楚的概念是如何在使用RxJS时调整订阅管理。在这方面,有三个主要的选择:
async
管道自动创建和删除订阅。如果您希望严格基于从可观察对象发出的数据进行UI更改,那么async
管道将在创建组件时轻松地创建对给定可观测对象的订阅,并在组件被销毁时删除这些订阅。这可以说是使用订阅的最干净的方式。例如:
@Component({
selector: 'my-component',
template: `
<div *ngFor="let value of value$ | async">
{{value}}
</div>
`
})
export class MyComponent {
public value$: Observable<String> = this.myValueService
.getValues()
.map(value => `Value: $value`);
constructor(myValueService: MyValueService) {}
}
Subscription
方法中创建类级ngOnInit
对象,然后在ngOnDestroy
方法中取消订阅,来管理组件中的订阅。当我需要访问组件代码中的订阅时,我倾向于这样做。在每个使用订阅的组件中使用ngOnInit
和ngOnDestroy
方法都会添加样板,但如果您需要在组件代码中订阅,则通常是必要的。例如:
@Component({
selector: 'my-component',
template: `
<div #myDiv></div>
`
})
export class MyComponent implements OnInit, OnDestroy {
private mySub: Subscription;
constructor(myValueService: MyValueService) {}
public ngOnInit() {
this.mySub = this.myValueService.getValue().subscribe((value) => {
console.log(value);
// Do something with value
});
}
public ngOnDestroy() {
this.mySub.unsubscribe();
}
}
first()
)限制订阅寿命。这是默认情况下,当您启动对HttpClient
可观察性的订阅时所做的事情。这样做的好处是不需要多少代码,但也可能导致订阅未被清除的情况(例如,如果可观察到的代码从未发出)。如果我想用一个可观察的东西做的所有事情都可以在视图中完成,那么我实际上总是使用选项1。在我的经验中,这涵盖了大多数情况。您始终可以使用中间可观察性来生成一个可观察的,如果需要的话,可以在视图中订阅。中间可观测值不会引起内存泄漏问题。
发布于 2018-03-15 10:54:17
另一种选择是使用可观测数据来检索数据,然后让角度变化检测处理其余的数据。随着角度的变化检测,它将更新UI的数据变化.没有必要再次订阅以获得更新。
例如,我有这种类型的UI:
我使用Http和一个可观察到的方法检索数据。但是,我利用角的变化检测来处理任何更新。
这是我的一份服务:
@Injectable()
export class MovieService {
private moviesUrl = 'api/movies';
private movies: IMovie[];
currentMovie: IMovie | null;
constructor(private http: HttpClient) { }
getMovies(): Observable<IMovie[]> {
if (this.movies) {
return of(this.movies);
}
return this.http.get<IMovie[]>(this.moviesUrl)
.pipe(
tap(data => console.log(JSON.stringify(data))),
tap(data => this.movies = data),
catchError(this.handleError)
);
}
// more stuff here
}
下面是上面右边显示的细节组件的完整代码(导入除外):
export class MovieDetailComponent implements OnInit {
pageTitle: string = 'Movie Detail';
errorMessage: string;
get movie(): IMovie | null {
return this.movieService.currentMovie;
}
constructor(private movieService: MovieService) {
}
ngOnInit(): void {
}
}
您可以在这里看到完整的示例(带有编辑):https://github.com/DeborahK/MovieHunter-communication/tree/master/MH-Take5
发布于 2018-03-15 11:33:36
在组件之间传递数据时,我发现RxJS BehaviorSubject
非常有用。
您也可以使用常规的RxJS Subject
来通过服务共享数据,但下面是我更喜欢BehaviorSubject的原因。
asobservable()
方法从行为主题中获得可观察的结果。示例
在服务中,我们将创建一个私有BehaviorSubject,它将保存消息的当前值。我们定义了一个currentMessage变量来处理这个数据流,作为其他组件将使用的一个可观察的数据流。最后,我们创建了一个函数,该函数调用BehaviorSubject
上的next来更改其值。
父组件、子组件和同级组件都得到相同的待遇。我们将DataService注入组件中,然后订阅可观察到的currentMessage,并将其值设置为等于消息变量。
现在,如果我们在这些组件中的任何一个中创建一个函数来更改消息的值。更新后的值将自动广播到所有其他组件。
shared.service.ts
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@Injectable()
export class SharedService {
private messageSource = new BehaviorSubject<string>("default message");
currentMessage = this.messageSource.asObservable();
constructor() { }
changeMessage(message: string) {
this.messageSource.next(message)
}
}
parent.component.ts
import { Component, OnInit } from '@angular/core';
import { SharedService } from "../shared.service";
@Component({
selector: 'app-sibling',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {
message: string;
constructor(private service: sharedService) { }
ngOnInit() {
this.service.currentMessage.subscribe(message => this.message = message)
}
newMessage() {
this.service.changeMessage("Hello from Sibling")
}
}
sibling.component.ts
import { Component, OnInit } from '@angular/core';
import { SharedService } from "../shared.service";
@Component({
selector: 'app-sibling',
template: `
{{message}}
<button (click)="newMessage()">New Message</button>
`,
styleUrls: ['./sibling.component.css']
})
export class SiblingComponent implements OnInit {
message: string;
constructor(private service: SharedService) { }
ngOnInit() {
this.service.currentMessage.subscribe(message => this.message = message)
}
newMessage() {
this.service.changeMessage("Hello from Sibling");
}
}
https://stackoverflow.com/questions/49307098
复制