gpt4 book ai didi

Angular 7,Reactive Form在有大数据时响应缓慢

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

我有一个非常复杂和庞大的数据,我必须在一个组件中围绕它构建一个 Reactive 表单。

我已经开发了表单。但是,当我在其中一个 input 字段中键入内容来编辑填充的数据时,它在更新该字段的值时响应极其缓慢。

我尝试使用 updateOn:'blur''submit' 但没有成功。

我的问题是,处理包含大量数据的表单的最佳做法是什么?

更新:这是我的StackBlitz .

注意:我创建了一个非常精简的实际实现版本,并且我在响应式表单中遇到了性能问题。

最佳答案

因此,在使用 StackBlitz 玩了大约一天之后,我找到了解决方案。我认为这会显着提高性能。

第 1 步:为您的数据模型创建接口(interface)

这样做会大大提高代码的清晰度和可读性。它还将使代码更易于管理和使用。因此,我们在这里为您的特定场景提供 interface 列表:

export interface Hotel {
id: string;
currencyId: string;
hotelYearId: string;
priceTaxTypeId: string;
code: string;
name: string;
createBy: string;
createDate: string;
lastUpdateBy: string;
lastUpdateDate: string;
remark: string;
internalRemark: string;
roomTypes: RoomType[];
}

export interface RoomType {
chk: boolean;
roomTypeId: string;
mealTypes: MealType[];
}

export interface MealType {
chk: boolean;
mealTypeId: string;
marketGroups: MarketGroup[];
}

export interface MarketGroup {
chk: boolean;
markets: Market[];
rateSegments: RateSegment[];
}

export interface Market {
marketId: string;
}

export interface RateSegment {
chk: boolean;
rateSegmentId: string;
hotelSeasons: HotelSeason[];
}

export interface HotelSeason {
chk: boolean;
hotelSeasonId: string;
rates: Rate[];
}

export interface Rate {
rateCodeId: string;
cancellationPolicyId: string;
dayFlag: string;
singlePrice: string;
doublePrice: string;
xbedPrice: string;
xbedChildPrice: string;
bfPrice: string;
bfChildPrice: string;
unitMonth: string;
unitDay: string;
minStay: number;
}

第 2 步:更改创建表单的方式

您创建表单的方式非常嘈杂。有一种明确的方法可以做到这一点。由于您已经在服务中创建表单,我建议您将创建表单的任务留给服务本身,并让您的组件免于执行任何此类任务。所以你的服务可以这样重构:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { FormBuilder, Validators } from '@angular/forms';
import { map } from 'rxjs/operators';

import { Hotel, RoomType, MealType, MarketGroup, Market, RateSegment, HotelSeason, Rate } from './hotel.model';

@Injectable()
export class UtilService {

constructor(
private readonly fb: FormBuilder,
private readonly http: HttpClient
) { }

getHotelForm() {
return this.getHotel().pipe(
map((apiResponse: any) => this.fb.group({
id: [apiResponse.id, Validators.required],
currencyId: [apiResponse.currencyId, Validators.required],
hotelYearId: [apiResponse.hotelYearId, Validators.required],
priceTaxTypeId: [apiResponse.priceTaxTypeId, Validators.required],
code: [apiResponse.code, Validators.required],
name: [apiResponse.name, Validators.required],
createBy: [apiResponse.createBy, Validators.required],
createDate: [apiResponse.createDate, Validators.required],
lastUpdateBy: [apiResponse.lastUpdateBy, Validators.required],
lastUpdateDate: [apiResponse.lastUpdateDate, Validators.required],
remark: [apiResponse.remark, Validators.required],
internalRemark: [apiResponse.internalRemark, Validators.required],
roomTypes: this.fb.array(apiResponse.roomTypes.map(roomType => this.generateRoomTypeForm(roomType)))
}))
);
}

private getHotel() {
return this.http.get('/assets/hotel.json');
}

private generateRoomTypeForm(roomType: RoomType) {

const roomTypeForm = this.fb.group({
chk: [roomType.chk, Validators.required],
roomTypeId: [roomType.roomTypeId, Validators.required],
mealTypes: this.fb.array(roomType.mealTypes.map(mealType => this.generateMealTypeForm(mealType)))
});

return roomTypeForm;
}

private generateMealTypeForm(mealType: MealType) {

const mealTypeForm = this.fb.group({
chk: [mealType.chk, Validators.required],
mealTypeId: [mealType.mealTypeId, Validators.required],
marketGroups: this.fb.array(mealType.marketGroups.map(marketGroup => this.generateMarketGroupForm(marketGroup)))
});

return mealTypeForm;
}

private generateMarketGroupForm(marketGroup: MarketGroup) {

const marketGroupForm = this.fb.group({
chk: [marketGroup.chk, Validators.required],
markets: this.fb.array(marketGroup.markets.map(market => this.generateMarketForm(market))),
rateSegments: this.fb.array(marketGroup.rateSegments.map(rateSegment => this.generateRateSegmentForm(rateSegment))),
});

return marketGroupForm;
}

private generateMarketForm(market: Market) {
return this.fb.group({
marketId: [market.marketId, Validators.required]
});
}

private generateRateSegmentForm(rateSegment: RateSegment) {
const rateSegmentForm = this.fb.group({
chk: [rateSegment.chk, Validators.required],
rateSegmentId: [rateSegment.rateSegmentId, Validators.required],
hotelSeasons: this.fb.array(rateSegment.hotelSeasons.map(hotelSeason => this.generateHotelSeasonForm(hotelSeason)))
});

return rateSegmentForm;
}

private generateHotelSeasonForm(hotelSeason: HotelSeason) {

const hotelSeasonForm = this.fb.group({
chk: [hotelSeason.chk, Validators.required],
hotelSeasonId: [hotelSeason.hotelSeasonId, Validators.required],
rates: this.fb.array(hotelSeason.rates.map(rate => this.generateRateForm(rate)))
});
return hotelSeasonForm;
}

private generateRateForm(rate: Rate) {
return this.fb.group({
rateCodeId: [rate.rateCodeId, Validators.required],
cancellationPolicyId: [rate.cancellationPolicyId, Validators.required],
dayFlag: [rate.dayFlag, Validators.required],
singlePrice: [rate.singlePrice, Validators.required],
doublePrice: [rate.doublePrice, Validators.required],
xbedPrice: [rate.xbedPrice, Validators.required],
xbedChildPrice: [rate.xbedChildPrice, Validators.required],
bfPrice: [rate.bfPrice, Validators.required],
bfChildPrice: [rate.bfChildPrice, Validators.required],
unitMonth: [rate.unitMonth, Validators.required],
unitDay: [rate.unitDay, Validators.required],
minStay: [rate.minStay, Validators.required]
});
}

}

第 3 步:利用上述服务:

这样做是为了获取 Form 并摆脱 methods,这些方法会返回模板中的 FormArray。这将使您的组件非常干净、清晰和简洁。

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';

import { UtilService } from '../app/util.service';

@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush
})

export class AppComponent {

form$: Observable<FormGroup> = this.util.getHotelForm();

constructor(private readonly util: UtilService) {
}

}

第 4 步:重构您的模板:

这是最重要的永远不要在深度嵌套的表单中调用 getter 或方法来获取 FormArray。或者更确切地说,通常以正常形式或在数据绑定(bind)语法中。因为它们会在每个更改检测周期中被调用,并且会降低您应用的性能。

Please refer to this lightning talk by Tanner Edwards from ng-conf 2018 to know more about it.

因此,您可以像这样重构您的组件模板:

<form 
*ngIf="form$ | async as form"
[formGroup]="form">
<div
formArrayName="roomTypes">
<div
*ngFor="let roomType of form.controls['roomTypes'].controls; let index = index"
[formGroupName]="index">
{{index}}
<div
formArrayName="mealTypes">
<div
*ngFor="let mealType of roomType.controls['mealTypes'].controls; let mealtypeIndex = index"
[formGroupName]="mealtypeIndex">
mealtype {{mealtypeIndex}}
<div
formArrayName="marketGroups">
<div
*ngFor="let marketGroup of mealType.controls['marketGroups'].controls; let marketGroupIndex = index"
[formGroupName]="marketGroupIndex">
marketGroupIndex {{marketGroupIndex}}
<div formArrayName="rateSegments">
<div
*ngFor="let rateSegment of marketGroup.controls['rateSegments'].controls; let rateSegmentIndex = index"
[formGroupName]="rateSegmentIndex">
rateSegmentIndex {{rateSegmentIndex}}
<div formArrayName="hotelSeasons">
<div
class="fifth_border"
*ngFor="let hotelseason of rateSegment.controls['hotelSeasons'].controls; let hotelseasonIndex = index"
[formGroupName]="hotelseasonIndex">
hotelseasonIndex {{hotelseasonIndex}}
<div formArrayName="rates">
<div
*ngFor="let rate of hotelseason.controls['rates'].controls; let rateIndex = index"
[formGroupName]="rateIndex">
<div style="display:flex;flex-flow;row">
<div>
<p>SGL</p>
<input class="input text_right" type="text" formControlName="singlePrice">
</div>
<div>
<p>DLB/TWN</p>
<input class="input text_right" type="text" formControlName="doublePrice">
</div>
<div>
<p>EX-Adult</p>
<input class="input text_right" type="text" formControlName="xbedPrice" >
</div>
<div>
<p>EX-Child</p>
<input class="input text_right" type="text" formControlName="xbedChildPrice">
</div>
<div>
<p>Adult BF</p>
<input class="input text_right" type="text" formControlName="bfPrice">
</div>
<div>
<p>Child BF</p>
<input class="input text_right" type="text" formControlName="bfChildPrice">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <pre>{{form.value | json}}</pre> -->
</form>

第 5 步:不要在这里停止

这还没有结束。这仅仅是个开始。您还可以将子窗体(marketGroups FormArray 中的 marketGroup FormGroup)抽象为一个单独的组件。然后你可以将它的 changeDetectionStrategy 设置为 OnPush。这会给你带来更好的表现。

Here's a StackBliz that you can refer to, to have a look at that solution.

完成所有这些将显着提高表单的性能。

希望对您有所帮助。如果我发现任何其他方法可以提高超出此限制的性能,我会尝试更新此答案。


Here's a Working Sample StackBlitz for your ref.


Here's a Detailed Medium Article about this that I wrote for AngularInDepth.


性能差异

我刚刚对您的实现以及我的实现进行了绩效审计,以评估在应用程序上执行的同一组步骤。

以下是您的实现摘要:

enter image description here

下面是重构实现的总结:

enter image description here

关于Angular 7,Reactive Form在有大数据时响应缓慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54532104/

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