与 Constructor 和 ngOnInit 之间的区别相关但不相同。
在 Angular 16 和 17 中,我们现在可以使用
takeUntilDestroyed
运算符和 Signals。这两个似乎在注入器上下文中工作得最好,或者至少有一个优点,你不需要通过一个。
所以问题(再次)是我们应该将初始化放在构造函数(或成员字段)中还是仍然使用
OnInit
?其次,使用构造函数而不是OnInit
有什么陷阱吗?
注意:初始化时我的意思是使用
httpClient
来获取要在页面上显示的数据。使用数据映射等设置 RxJS 管道。读取路由参数等
搁置以下内容:
OnInit
变量,我们需要使用 OnChanges
或 @Input()
根据旧 Angular.io 站点的 Component Lifecycle 文档:
组件的构造应该便宜且安全。例如,您不应该在组件构造函数中获取数据。您不必担心新组件在测试中创建时或在您决定显示它之前会尝试联系远程服务器。 ngOnInit() 是组件获取其初始数据的好地方。
但是新的 Angular.dev 站点中不存在此文档。
他们的新教程之一在构造函数中也有数据调用:
constructor() {
this.housingService.getAllHousingLocations().then((housingLocationList: HousingLocation[]) => {
this.housingLocationList = housingLocationList;
this.filteredLocationList = housingLocationList;
});
}
Angular 16/17 似乎正朝着在注入上下文(成员字段或构造函数)中完成更多初始化的方向发展。这对性能、稳定性、未来发展有影响吗?
最好在成员字段声明中初始化事物。通过这种方式,您可以将字段声明为
readonly
,并且您可以在同一行中声明它们的类型,并且通常可以直接推断出来。
class ExampleComponent {
private readonly userService = inject(UserService);
private readonly users = this.userService.getUsers();
}
如果某些字段在构造函数中初始化(而不是在参数列表中),那么您将需要 2 行 - 一行用于声明字段(及其类型),另一行用于初始化它:
class ExampleComponent {
private readonly users: Observable<User[]>;
constructor(private readonly userService: UserService) {
this.users = this.userService.getUsers();
}
}
另外,如果某些字段是在构造函数中初始化的,那么在字段初始化之前使用字段时可能会遇到这样的情况:
class ExampleComponent {
private readonly users: Observable<User[]>;
constructor(private readonly userService: UserService) {
this.users = this.userService.getUsers();
}
private readonly emails = this.users.pipe(
map((users) => users.map(user => user.email))
);
}
无论
emails
位于何处,它都会在constructor()
之前被初始化,并且你会得到一个错误。而实际上代码并不是那么短和简单,所以很容易出现这种情况。
仅当您需要一次读取多个 ngOnInit()
属性并基于其中的多个属性执行逻辑时,才需要
ngOnChanges()
和 Input()
。不过,我建议使用 setter 和 computed()
:
class ExampleComponent {
private readonly $isReadonly = signal<boolean>(false);
private readonly $hasEditPermissions = signal<boolean>(true);
// 🍒
private readonly $isEditButtonEnabled = computed(() => {
return !this.$isReadonly() && this.$hasEditPermissions();
});
@Input() set isReadonly(isReadonly: boolean) {
this.$isReadonly.set(isReadonly);
}
@Input() set hasEditPermissions(hasEditPermissions: boolean) {
this.$hasEditPermissions.set(hasEditPermissions);
}
}
您不必担心新组件在测试中创建时或在您决定显示它之前会尝试联系远程服务器
在测试中,通过mock解决。
|async
管道和@defer
解决了第二个问题。另外,如果您想将某些可观察量转换为信号,并且不想订阅直到模板的该部分可见,NG 扩展库中有一个辅助函数:toLazySignal()
。