在 Angular 中获取路由参数的有效方法
Efficient way to get route parameter in Angular
如何更有效地使用路由器 Observables?例如,如果我需要加载单个路由参数(假设我们有一条像 /some-resource/:id
这样的路由),我需要订阅路由器事件,然后订阅路由参数以获取值。这需要两次订阅和两次退订。
我愿意:
- 减少样板代码
- 使代码更具可读性
- 取消订阅
样本
export class SomeComponent implements OnInit, OnDestroy {
private routerSub: Subscription;
private routeSub: Subscription;
someResource: Observable<SomeResourceType>;
constructor(private someService: SomeService,
private route: ActivatedRoute,
private router: Router) {
this.routerSub = this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
this.routeSub = this.route.params.subscribe((params) => {
if (params['id']) {
this.someResource = this.someService.findById(params['id']);
// will access the resource using async pipe later
}
});
}
});
}
ngOnInit(): void {
}
ngOnDestroy(): void {
this.routerSub.unsubscribe();
this.routeSub.unsubscribe();
}
}
如果由于某种原因组件未被 angular 销毁,但仍使用不同的路由参数加载,则需要事件订阅来刷新数据 stackblitz 示例:https://stackblitz.com/edit/angular-router-basic-example-695kpb
只要没有人发布更好的解决方案,这里是我的:
我定义了一个 RouterHelperService
,这使得这个过程更容易一些。问题之一是,如果您尝试直接在您的服务中注入 ActivatedRoute
实例,您将丢失参数,因此您需要将它从您的组件传递到服务。
import { Injectable } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { filter, flatMap, map } from 'rxjs/operators';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class RouterHelperService {
constructor(private router: Router) {
}
onNavigationEndReadParamByKey(route: ActivatedRoute, key: string): Observable<string> {
return this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
flatMap(() => {
return route.params.pipe(
filter(params => params[key]),
map(params => params[key])
);
})
);
}
}
这样,在我的组件中,我可以通过一次调用和一次订阅来调用它。
export class SomeComponent implements OnInit, OnDestroy {
private routeSub: Subscription;
someResource: Observable<SomeResourceType>;
constructor(private someService: SomeService,
private route: ActivatedRoute) {
this.routeSub = this.routerHelper.onNavigationEndReadParamByKey(this.route, 'id').subscribe((id) => {
this.someResource = this.someService.findById(+id); //+id to convert it from a string to a number
});
}
ngOnInit(): void {
}
ngOnDestroy(): void {
this.routeSub.unsubscribe();
}
}
试试这个:
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const id = this.route.snapshot.params['id'];
}
您可以为此使用激活的路线。
constructor(route: ActivatedRoute) {
this.id$ = route.params
.pipe(pluck('id'));
}
你可以使用 pluck。 pluck('id')
与map(value => value.id)
基本相同。如果你不想有一个流,而是实际的价值,你可以做同样的事情并订阅它。但是如果你这样做了,不要忘记取消订阅 Observable。您可以使用 take until 运算符来执行此操作。
id;
private _destroyed$ = new Subject<any>();
constructor(route: ActivatedRoute) {
route.params
.pipe(
takeUntil(this._destroyed$),
pluck('id')
).subscribe(id => this.id = id);
}
ngOnDestroy() {
this._destroyed$.next();
this._destroyed$.complete();
}
最快的方式,不支持组件重新加载:
constructor(
route: ActivatedRoute,
) {
const myParam = route.snapshot.params.idThread;
}
使用paramMap和'new' RxJs语法,支持组件重载:
constructor(
route: ActivatedRoute,
) {
route.paramMap.subscribe({
next: params => {
const myParam = params.get('myParam');
}
});
}
注意:在这种情况下取消订阅不是强制性的,不应导致内存泄漏
如何更有效地使用路由器 Observables?例如,如果我需要加载单个路由参数(假设我们有一条像 /some-resource/:id
这样的路由),我需要订阅路由器事件,然后订阅路由参数以获取值。这需要两次订阅和两次退订。
我愿意:
- 减少样板代码
- 使代码更具可读性
- 取消订阅
样本
export class SomeComponent implements OnInit, OnDestroy {
private routerSub: Subscription;
private routeSub: Subscription;
someResource: Observable<SomeResourceType>;
constructor(private someService: SomeService,
private route: ActivatedRoute,
private router: Router) {
this.routerSub = this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
this.routeSub = this.route.params.subscribe((params) => {
if (params['id']) {
this.someResource = this.someService.findById(params['id']);
// will access the resource using async pipe later
}
});
}
});
}
ngOnInit(): void {
}
ngOnDestroy(): void {
this.routerSub.unsubscribe();
this.routeSub.unsubscribe();
}
}
如果由于某种原因组件未被 angular 销毁,但仍使用不同的路由参数加载,则需要事件订阅来刷新数据 stackblitz 示例:https://stackblitz.com/edit/angular-router-basic-example-695kpb
只要没有人发布更好的解决方案,这里是我的:
我定义了一个 RouterHelperService
,这使得这个过程更容易一些。问题之一是,如果您尝试直接在您的服务中注入 ActivatedRoute
实例,您将丢失参数,因此您需要将它从您的组件传递到服务。
import { Injectable } from '@angular/core';
import { ActivatedRoute, NavigationEnd, Router } from '@angular/router';
import { filter, flatMap, map } from 'rxjs/operators';
import { Observable } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class RouterHelperService {
constructor(private router: Router) {
}
onNavigationEndReadParamByKey(route: ActivatedRoute, key: string): Observable<string> {
return this.router.events.pipe(
filter(event => event instanceof NavigationEnd),
flatMap(() => {
return route.params.pipe(
filter(params => params[key]),
map(params => params[key])
);
})
);
}
}
这样,在我的组件中,我可以通过一次调用和一次订阅来调用它。
export class SomeComponent implements OnInit, OnDestroy {
private routeSub: Subscription;
someResource: Observable<SomeResourceType>;
constructor(private someService: SomeService,
private route: ActivatedRoute) {
this.routeSub = this.routerHelper.onNavigationEndReadParamByKey(this.route, 'id').subscribe((id) => {
this.someResource = this.someService.findById(+id); //+id to convert it from a string to a number
});
}
ngOnInit(): void {
}
ngOnDestroy(): void {
this.routeSub.unsubscribe();
}
}
试试这个:
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const id = this.route.snapshot.params['id'];
}
您可以为此使用激活的路线。
constructor(route: ActivatedRoute) {
this.id$ = route.params
.pipe(pluck('id'));
}
你可以使用 pluck。 pluck('id')
与map(value => value.id)
基本相同。如果你不想有一个流,而是实际的价值,你可以做同样的事情并订阅它。但是如果你这样做了,不要忘记取消订阅 Observable。您可以使用 take until 运算符来执行此操作。
id;
private _destroyed$ = new Subject<any>();
constructor(route: ActivatedRoute) {
route.params
.pipe(
takeUntil(this._destroyed$),
pluck('id')
).subscribe(id => this.id = id);
}
ngOnDestroy() {
this._destroyed$.next();
this._destroyed$.complete();
}
最快的方式,不支持组件重新加载:
constructor(
route: ActivatedRoute,
) {
const myParam = route.snapshot.params.idThread;
}
使用paramMap和'new' RxJs语法,支持组件重载:
constructor(
route: ActivatedRoute,
) {
route.paramMap.subscribe({
next: params => {
const myParam = params.get('myParam');
}
});
}
注意:在这种情况下取消订阅不是强制性的,不应导致内存泄漏