在使用angular时你应该避免的几个坏习惯

82 阅读3分钟

错误一:不要将正在处理的逻辑放在tap中

不要将要处理的逻辑放在tap操作符中,并且保持空的订阅以防有很多订阅者

为什么?

tap 运算符主要用于缓存或日志记录等副作用,如果您将逻辑放在那里,每个订阅者都会调用 tap 逻辑,甚至不需要它。但这不是通用规则,它取决于您的用例,如果真的希望所有订阅者都具有此逻辑,或者只有一个订阅者并且想使用“异步管道”,那么则可以这样使用

示例:

tap((data: ObjectType[]) => { 
   if (!data.every((status) => status.value === "Success")) {  
   const failed = data.filter( 
   (status) => status.value !== "Success"); 
   const failedData = failed.reduce((previous, current) => `${previous}${previous.length ? ',' : ''}'${current.personName}'`, );            
   const reason = data.map((obj) => obj.errorMessage).join('\n');
   this.infoService.warn( `Failed uploading data${ failed.length > 1 ? 's' : ''} ${failedData}: Reasons: ${reason}`); 
   } else {       
   this.infoService.info(`File${data.length > 1 ? 's' : ''} successfully done`);}
 }),

解决方案:

使用subscribe代替tap去处理逻辑

错误二:不要使用常规的error

对于错误处理来说,自带的error仅是错误记录不会抛出错误,只是知道有一些报错且你的observable无法继续执行

// 发出错误
const source = throwError('This is an error!');
// 优雅地处理错误,并返回带有错误信息的 observable
source.subscribe(
  val => {console.log(val)},
  //只能写成console.error
  err => {of(`I caught: ${err}`)}
)

解决方案:

使用rxjs提供的错误处理操作符去处理以及重试逻辑

// 发出错误
const source = throwError('This is an error!');
// 优雅地处理错误,并返回带有错误信息的 observable
source.pipe(catchError(val => of(`I caught: ${val}`))).subscribe(val => console.log(val))

错误三: 不要写三四千行的组件

不要把每件事都放在一个组件中,原因有以下几点:

  • 难以去重构
  • 对其他开发人员来说可读性较差
  • 破坏了组件式开发的规则

解决方案:

始终考虑可复用组件以及父子组件的分离

错误四: 不要在模板中使用大量内联式的代码

  • 影响应用的性能
  • 将给后续的重构带来困难

示例

@Component({
   template: `<p>Welcome {{ fullName() }}</p>`
})

export class PersonComponent{
  @Input() person: { firstName: string, lastName: string};
  constructor(){}
  fullName(){
     return this.person..firstName + '' + this.person.lastName
  }
}

解决方案

对数据进行计算组合,使用管道提升其稳定性和可复用性

@Component({
   template: `<p>Welcome {{ name | nameToString }}</p>`
})

export class PersonComponent{
  @Input() person: { firstName: string, lastName: string};
  constructor(){}
}

@Pipe({
   name: 'nameToString'
})
export class IdPathPipe implement PipeTransform {
  transform(value): string {
    return value.firstName = value.lastName;
  }
}

错误五: 不要使用promise代替observable

如果你将 Promise 与 Angular 组件一起用于 HTTP 请求处理或其他任何事情,你应该考虑这些限制:

  • promise不容易取消
  • promise不容易重试

不要在订阅中映射或转换数据

假如有很多订阅者需要相同的转换,那么就会造成大量的代码冗余 并且订阅是一个同步调用,我们会被阻塞直到转换完成

示例

this.http.get("https://swapi.dev/api/people/1"
    .subscribe(luke => {
       name: responese.name,
       birthYear: response.birth_year,
       height: Number(response.height),
       weight: Number(response.weight),
       eyeColoe: response.eye_color
    })
    )

解决方案

您应该使用 Rxjs 映射运算符来预处理您的数据,因为许多订阅者可以获得您的结果,并且您将获得一些代码逻辑(可重用性)。

this.http.get("https://swapi.dev/api/people/1"
    .pipe(map(response => ({
       name: responese.name,
       birthYear: response.birth_year,
       height: Number(response.height),
       weight: Number(response.weight),
       eyeColoe: response.eye_color
    }))
    .subscribe(luke => {
       console.log(luke);
    })
    )

错误六: 不要把任意module都存放在sharedmodule中

共享模块是一种推荐的angular架构模式,用于组织常用的管道、指令和组件。但是随着应用程序大小的增长,您会发现自己在组件中导入了不需要的依赖项,这会影响您的项目包大小

优化: 在分离出来的文件中定义常量

推荐定义多个组件之间通用的全局常量,当您希望在整个应用程序中使用通用行为时很有用

示例

export class DataTableConstants {
  public static ItemPerPage: number = 50;
  public static PageSize: number[] = [10, 50, 100, 200, 500];
  public static AllowFiltering: boolean = true;
}

import { Component, OnInit } from '@angular/core';
import { DataTableConstants } from './globals/datatable-constants';
   
@Component({
  selector: 'app-example',
  templateUrl: './app.example.html',
  styleUrls: ['./app.example.css']
})
export class AppExampleComponent implements OnInit{
    itemPerPage = DataTableConstants.ItemPerPage;
    pageSize = DataTableConstants.PageSize;
    allowFiltering = DataTableConstants.AllowFiltering;
  
    ngOnInit() { 
        console.log(this.itemPerPage);
        console.log(this.pageSize);
        console.log(this.allowFiltering);
    }
}