gpt4 book ai didi

angular - 将代码从 ChangeDetectionStrategy.Default 重构为 ChangeDetectionStrategy.OnPush

转载 作者:太空狗 更新时间:2023-10-29 17:03:26 25 4
gpt4 key购买 nike

在过去几年从事 React 项目之后,我才开始接触 Angular。

我有一个使用 changeDetection: ChangeDetectionStrategy.OnPush 的组件,但我不喜欢我的解决方案。问题是我发现很难找到 ChangeDetectionStrategy.OnPush

的任何好的现实世界示例

例如,我有一个组件有点像这样:

  files: Uploads[] = [];

get canUpload() {
return this.files.length > 0l
}

get isUploading() {
return this.files.length > 0 && this.files.some((f) => f.state === FileUpLoadState.uploading);
}

get activeFiles() {
return this.files.filter((f) => f.state !== FileUpLoadState.success);
}

uploadFiles() {
if (!this.files.length) {
return;
}

const fileList: FileList = (event.target as HTMLInputElement).files;

for (const uploadedFile of Array.prototype.slice.call(fileList)) {
// do stuff
this.files.push(new Upload(file));
}

}

我有像这样在模板中使用的这些属性;

 <button (click)="uploadFiles()" [disabled]="!this.canUpload">Upload</button>

我真的不喜欢这样,使用默认的更改检测不会扩展,而且何时传播更改不在我的控制范围内。

如何重构此代码以使用 OnPush 更改检测?

最佳答案

人们回答你,但他们不会解释你。

OnPush 策略是变更检测中最有效的策略。 Angular 默认不实现它,因为新手习惯于看到魔法(即当您开始使用 Angular 时,默认策略对错误更友好且更容易理解)。

为了检测变化,Angular 会监听您 View 上的事件。使用默认策略,可能会导致大量无用的更改检测。

在推送策略中,您可以控制何时触发更改检测。

在这两种情况下,Angular 都使用内存引用来了解数据何时更新。这就是对象不可变性在 Angular 中如此重要的原因,也是响应式(Reactive)编程如此有效的原因。

话虽这么说,如果你想切换到推送策略,你应该使用以下内容:

  // files: Uploads[] = [];
files: BehaviorSubject<Uploads[]> = new BehaviorSubject([]);

add(item) {
this.files.pipe(first()).subscribe(files => this.files.next([...files, item]));
}

get canUpload() {
// return this.files.length > 0l
return this.files.pipe(
map(files => files.length),
map(size => !!size)
);
}

get isUploading() {
// return this.files.length > 0 && this.files.some((f) => f.state === FileUpLoadState.uploading);
return this.files.pipe(
startWith(false),
filter(files => !!files.length),
filter(files => files.some(f => f.state === FileUpLoadState.uploading)),
map(() => true)
);
}

get activeFiles() {
// return this.files.filter((f) => f.state !== FileUpLoadState.success);
return this.files.pipe(
map(files => files.filter(f => f.state !== FileUpLoadState.success)),
);
}

uploadFiles() {
/*
if (!this.files.length) {
return;
}

const fileList: FileList = (event.target as HTMLInputElement).files;

for (const uploadedFile of Array.prototype.slice.call(fileList)) {
// do stuff
this.files.push(new Upload(file));
}
*/
this.files.pipe(
filter(files => !!files.length),
map(files => (event.target as HTMLInputElement).files),
first()
).subscribe(files => {
for (const uploadedFile of Array.prototype.slice.call(fileList)) {
// do stuff
this.add(new Upload(file));
}
});
}

这是您可以执行的众多实现之一。我不确定这是否会按您期望的方式工作,我只是“翻译”了代码,因此您可能需要进行一两次调整。

这样,当您的收藏发生变化时,您的 View 会自动更新。您无需执行任何操作。这符合推送策略,因为响应式编程会触发变更检测。

并且因为每个 getter 都依赖于您的 BehaviorSubject,所以它们都会在该主题的每次更改时更新。

只是一个“缺点”(实际上不是),就是在您的组件模板中,您必须使用异步管道:

 <ng-container *ngIf="canUpload | async">...</ng-container>

如果您有任何问题,请随时提出!

关于angular - 将代码从 ChangeDetectionStrategy.Default 重构为 ChangeDetectionStrategy.OnPush,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54637334/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com