Javascript 仅当对象的属性已更改时,角度更新视图
我在angular应用程序中每隔15秒从web api轮询一次数据。这将导致我的角材质展开面板返回其未展开的默认位置,并使网站变慢,这将给用户带来不便。如果用于更新视图的数据与视图的当前数据不同,是否有办法只更新视图 下面是我的组件的代码Javascript 仅当对象的属性已更改时,角度更新视图,javascript,angular,typescript,asp.net-web-api,ngrx,Javascript,Angular,Typescript,Asp.net Web Api,Ngrx,我在angular应用程序中每隔15秒从web api轮询一次数据。这将导致我的角材质展开面板返回其未展开的默认位置,并使网站变慢,这将给用户带来不便。如果用于更新视图的数据与视图的当前数据不同,是否有办法只更新视图 下面是我的组件的代码 //component.html <mat-expansion-panel *ngFor="let item of vehicleDetail?.histalarm" cl
//component.html
<mat-expansion-panel *ngFor="let item of vehicleDetail?.histalarm" class="expansion-panel">
<mat-expansion-panel-header>
<p class="mobil-font-size">
<!-- The date is highlighted in the color of the severity of the alarm-->
<span [ngClass]="getDetailColors(item.severity)"> {{ item.timestamp}} </span>
<span style="font-weight: bold;"> - Description: </span> {{ item.description }}.
</p>
</mat-expansion-panel-header>
<!-- All extra info is being displayed below. Translators is used for kind and severity
to make them more readable-->
<p>
<span class="bold"> More Information </span>
<br>
<span class="bold"> Severity: </span> {{ severityTranslator(item.severity) }}
<br>
<span class="bold"> Details: </span> {{item.details }}
</p>
</mat-expansion-panel>
目前我最担心的是,当用户试图阅读详细信息时,扩展面板会不断更新。这是因为我告诉扩展面板每15秒更新一次,因为我希望更新时间戳和其他内容。然而,不断的干扰令人沮丧,这就是我试图解决的问题
编辑
发布减速器的代码以及请求的
import * as fromVehicleDetails from '../actions/vehicledetails.action';
import { VehicleDetail } from '../../models/vehicle-detail';
export interface VehicleDetailsState {
entities: { [id: number]: VehicleDetail };
loaded: boolean;
loading: boolean;
}
export const initialState: VehicleDetailsState = {
entities: {},
loaded: false,
loading: false
};
export function reducer(
state = initialState,
action: fromVehicleDetails.VehicleDetailsAction
): VehicleDetailsState {
switch (action.type) {
case fromVehicleDetails.LOAD_VEHICLEDETAILS: {
return {
...state,
loading: true
};
}
case fromVehicleDetails.LOAD_VEHICLEDETAILS_SUCCESS: {
const vehicledetails = action.payload;
const entities = vehicledetails.reduce(
(
entity: { [id: number]: VehicleDetail },
vehicledetail: VehicleDetail
) => {
return {
...entity,
[vehicledetail.id]: vehicledetail
};
},
{
...state.entities
}
);
return {
...state,
loaded: true,
loading: false,
entities
};
}
case fromVehicleDetails.LOAD_VEHICLEDETAILS_FAIL: {
return {
...state,
loaded: false,
loading: false
};
}
}
return state;
}
export const getVehicleDetailsEntities = (state: VehicleDetailsState) =>
state.entities;
export const getVehicleDetailsLoaded = (state: VehicleDetailsState) =>
state.loaded;
export const getVehicleDetailsLoading = (state: VehicleDetailsState) =>
state.loading;
您遇到的问题是,每次刷新数据时都要替换处于您状态的对象。这意味着NGRX将通知任何订阅者它已更改的对象的选择,这意味着Angular将重新绘制UI,因为可观察对象已发出 为了避免额外的重新绘制,您需要在reducer中评估详细信息是否已更改,然后仅在详细信息已更改时返回更新状态。要计算详细信息是否已更改,您需要对API返回的数据与当前处于状态的数据进行“深度相等”检查,例如:
case fromVehicleDetails.LOAD_VEHICLEDETAILS_SUCCESS: {
const vehicledetails = action.payload;
const entities = vehicledetails.reduce(
(
entity: { [id: number]: VehicleDetail },
vehicledetail: VehicleDetail
) => {
return {
...entity,
[vehicledetail.id]: vehicledetail
};
},
{
...state.entities
}
);
// Add logic to check if entities has changed, and not return the updated entities if they have not:
if (deepEqual(entities, state.entities)) return { ...state, loaded: true, loading: false };
// Entities have changed, return updated state with new entities:
return {
...state,
loaded: true,
loading: false,
entities: entities
};
}
然后需要实现一个deepEquals函数来评估新实体和旧实体是否相同。库,如或您可以编写自己的特定检查,了解刷新时可能更改的属性和内容。我们可以查看组件代码吗?您可以提供相关代码以便我们在这里帮助您吗?感谢您的回复@Raph and crueengine,它已更新。如果您想让我发布更多相关代码,请告诉我。您是否尝试过使用distinctUntilChanged运算符?看看这个。这可能会有帮助,你可以发布你的NGRX reducer的代码,更新从API接收到的数据到状态吗?非常感谢你的回复!时间戳将始终更新,因此每个对象都将不同于前一个对象。有什么办法让我绕过这件事吗?因为我想不断地更新时间戳。或者这是不可能的,因为这两个属性属于同一个对象?如果您希望在显示时更新时间戳,显然您必须更新对象,并且无法避免重画。如果您不关心时间戳,则可以在执行reduce时将其从vehicledetail对象中删除(例如,
delete vehicledetail.timestamp
在reduce
回调的返回行之前)。另一个选项是将“上次更新的时间戳”分解到不同的树中,并单独选择,因此,如果时间戳更改,但其他细节没有更改,则可以为细节保留相同的对象@maac
case fromVehicleDetails.LOAD_VEHICLEDETAILS_SUCCESS: {
const vehicledetails = action.payload;
const entities = vehicledetails.reduce(
(
entity: { [id: number]: VehicleDetail },
vehicledetail: VehicleDetail
) => {
return {
...entity,
[vehicledetail.id]: vehicledetail
};
},
{
...state.entities
}
);
// Add logic to check if entities has changed, and not return the updated entities if they have not:
if (deepEqual(entities, state.entities)) return { ...state, loaded: true, loading: false };
// Entities have changed, return updated state with new entities:
return {
...state,
loaded: true,
loading: false,
entities: entities
};
}