简洁高效的Angular最佳实践细节

本文介绍了四个Angular开发的最佳实践,包括利用trackBy优化DOM更新,使用async管道处理Observable以避免内存泄漏,利用字符串枚举增强类型安全性,以及遵循DRY原则减少代码重复。通过这些实践,可以提升应用性能并降低维护难度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、trackBy

当使用ngFor循环模板中的数组时,将其与trackBy函数一起使用,该函数将为每个项返回唯一标识符。

当数组更改时,Angular会重新呈现整个DOM树。如果你使用trackBy,Angular将知道哪个元素已经改变,并且只会对该特定元素进行DOM更改。

例如:

<li *ngFor=“let item of items”> {{item}} </li>

优化为:

//在模板中
<li *ngFor=“let item of items; trackBy:trackByFn”> {{item}} </li> 
//在组件
trackByFn(index,item)中{     
   return item.id; 对应项目唯一的ID 
}

2、async

避免从组件订阅observable,而是从模板订阅observable。

async管道可以自动取消订阅,不再需要手动取消订阅,使代码更简单。忘记取消订阅会导致内存泄漏。通过使用lint规则来检测未订阅的可观察量,也可以减轻这种风险。

这也会阻止组件成为有状态,并引入数据在订阅之外变异的错误。

例如:

// template
<p>{{ textToDisplay }}</p>
// component
iAmAnObservable
    .pipe(
       map(value => value.item),
       takeUntil(this._destroyed$)
     )
    .subscribe(item => this.textToDisplay = item);

优化为:

// template
<p>{{ textToDisplay$ | async }}</p>
// component
this.textToDisplay$ = iAmAnObservable
    .pipe(
       map(value => value.item)
     );

3、字符串枚举

善用枚举,以在编译时发现错误。ng-zorro-antd源码中几乎在所有暴露@Input(): String的地方使用了此条规则。

例如:

private myStringValue:string; 
if(itShouldHaveFirstValue){ 
   myStringValue ='First'; 
} else { 
   myStringValue ='Second' 
}

优化为:

private myStringValue: 'First' | 'Second';
if (itShouldHaveFirstValue) {
   myStringValue = 'First';
} else {
   myStringValue = 'Other'
}
// This will give the below error
Type '"Other"' is not assignable to type '"First" | "Second"'
(property) AppComponent.myValue: "First" | "Second"

4、DRY

Don't Repeat Yourself! 这是新手程序员容易犯的错误之一。我在公司检视其他同事的代码时,经常发现其代码中包含两段几乎相同的代码,甚至两个几乎相同的组件!

在我刚学编程时我就发现,使用复制粘贴产生相似的代码,不仅容易产生难找的bug,而且在修改时难以下手。

在这些情况下,使用各种手段抽象、提取重复代码。这意味着只需要改变一个地方,测试一件事。将较少的重复代码发送给用户意味着应用程序将更快。

提炼代码的过程不仅仅能锻炼逻辑能力,也能在这个过程中学到一些新知识。

例如:

@Component({
  selector: 'person',
  template: `
    <div [formGroup]="form">
      <div>
        <label>Name</label>
        <input type="text" formControlName="name" />
      </div>
      <div>
        <label>Contact info</label>
        <input type="text" formControlName="contactInfo" />
      </div>
      <div>
        <label>Allergies</label>
        <input type="text" formControlName="allergies" />
      </div>
      <strong>{{ form.valid ? 'valid' : 'invalid' }}</strong>
    </div>
  `,
})
export class PersonComponent {
  form = this.formBuilder.group({
    name: ['', Validators.required],
    contactInfo: [''],
    allergies: [''],
  })

  constructor(private formBuilder: FormBuilder) {}
}

这个表单如果想修改Require验证逻辑在其他地方使用,应该怎么做?

提供一种思路,使用不同的属性型指令提供不同的改装逻辑。

优化后:

@Directive({
  selector: 'person[stage-one]',
})
export class StageOneDirective {
  constructor(host: PersonComponent) {
    host.form.get('contactInfo').setValidators([Validators.required])
  }
}
@Directive({
  selector: 'person[stage-two]',
})
export class StageTwoDirective {
  constructor(host: PersonComponent) {
    host.form.get('contactInfo').setValidators([Validators.required])
    host.form.get('allergies').setValidators([Validators.required])
  }
}
<!-- Only the name is required -->
<person></person>

<!-- The name and the contactInfo are required -->
<person stage-one></person>

<!-- All fields are required -->
<person stage-two></person>

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值