![](/img/trans.png)
[英]Angular 2 proper way to template a [routerLink] in a child component
[英]Angular proper way of displaying model calculated data on template
考慮一個Person
model,例如:
class Person {
firstName: string;
lastName: string;
}
以及從中計算/派生的數據,例如`${firstName} ${lastName}`
的fullName
(這只是一個示例,因為計算可能更復雜和繁重)。
在組件模板上顯示計算數據的正確方法是什么? 考慮到:
{{ person.firstName }} {{ person.lastName }}
;OnPush
更改檢測策略,在模板上使用 getter 或方法也不可行; 我考慮過對Person
model 使用不可變的方法,並僅在構造函數中計算派生屬性:
class Person {
firstName: string;
lastName: string;
readonly fullName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
this.fullName = `${firstName} ${lastName}`;
}
}
顯然,使用這種方法我不能做person.firstName = 'Changed'
來更新fullName
屬性,但我必須做person = new Person('Changed', person.lastName)
。
我已經考慮將readonly
也應用於firstName
和lastName
以確保不變性模式,但是通過這種方式,我無法在另一個模板上下文中使用Person
model,例如,我需要將firstName
和lastName
綁定到某些輸入楷模。
我真的很想知道正確處理這種常見情況的標准/正確/最佳實踐方法是什么。
我會考慮使用屬性(獲取)
class Person {
firstName: string;
lastName: string;
get fullName(): string { return `${this.firstName} ${this.lastName}`;}
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
}
}
編輯
為了優化經常發生的變化並減少重新計算,您可以使用 Subject 和 pipe 它與 debounceTime。
class Person{
private _firstName: string;
private _lastName: string;
private _fullName: string;
private _debounceFirstname = new Subject<string>();
private _debounceLastname = new Subject<string>();
constructor(firstName: string, lastName: string) {
this._firstName = firstName;
this._lastName = lastName;
this._debounceFirstname
.pipe(debounceTime(300)).subscribe((value: string) => this.firstName = value);
this._debounceLastname
.pipe(debounceTime(300)).subscribe((value: string) => this.lastName = value);
this.changeCalculation();
}
get firstName(): string {
return this._firstName;
}
set firstName(value: string) {
this._firstName = value;
this.changeCalculation();
}
get lastName(): string {
return this._lastName;
}
set lastName(value: string) {
this._lastName = value;
this.changeCalculation();
}
get fullName(): string{
return this._fullName;
}
private changeCalculation(): void {
this._fullName= `${this.firstName} ${this.lastName}`;
}
}
我看到您想避免使用 getter 和方法,但我並不完全相信這種方法的性能缺點是如此昂貴。 一般來說,如果那些 getter 和方法不做一些繁重的工作,我認為你不應該放棄它們。 當然,與您的情況一樣,這些操作可能更復雜。
我處理這種情況的主觀方法是使用 getter 和 setter,同時盡可能避免fullName
計算:
class Person {
_firstName: string;
_lastName: string;
_fullName: string;
constructor(firstName: string, lastName: string) {
this.firstName = firstName;
this.lastName = lastName;
this._fullName = `${firstName} ${lastName}`; // First setting of the fullName
}
get firstName() {
return this._firstName;
}
set firstName(newFirstName: string) {
if (newFirstName !== this._firstName) {
// Update the full name
this._fullName = `${newFirstName} ${this._lastName}`;
this._firstName = newFirstName;
}
}
get lastName() {
return this._lastName;
}
set lastName(newLastName: string) {
if (newLastName !== this._lastName) {
// Update the full name
this._fullName = `${this._firstName} ${newLastName}`;
this._lastName = newLastName;
}
}
get fullName() {
// Memoizing the full name
if (!this._fullName) {
// The full name is not going to be recalculated every time
this._fullName = `${this._firstName} ${this._lastName}`;
}
return this._fullName;
}
}
這是一個反應式的例子。 有些人認為在 RXJS 中使用 BehaviorSubject 有點反模式,但這是一個不同的討論。
模板代碼 - 使用異步 pipe 從 observable 中獲取值並管理訂閱。
<div>{{myPerson.fullName$ | async}}</div>
Model 代碼 - 定義名字和姓氏的行為主體。 使用 combinelatest 檢測名字或姓氏的更改。
class Person {
private firstNameSubject: BehaviorSubject<string>;
private lastNameSubject: BehaviorSubject<string>;
fullName$: Observable<string>;
constructor(firstName: string, lastName: string) {
this.firstNameSubject = new BehaviorSubject(firstName);
this.lastNameSubject = new BehaviorSubject(lastName);
this.fullName$ = combineLatest([firstName, lastName]).pipe(
map(([first, last]) => computeFullName(first, last)),
shareReplay(1) //make our stream replayable to so we don't need to recompute the value per subscription
);
}
setfirstName(newFirstName: string) {
this.firstNameSubject.next(newFirstName);
}
setlastName(newLastName: string) {
this.lastNameSubject.next(newLastName);
}
getFirstName() {
return this.firstNameSubject.value;
}
getLastName() {
return this.lastNameSubject.value;
}
}
export function computeFullName(firstName: string, lastName: string) {
return `${firstName} ${lastName}`;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.