【问题标题】:Angular update view only if the properties of the object has changed仅当对象的属性已更改时,角度更新视图
【发布时间】:2019-01-20 05:22:18
【问题描述】:

我每 15 秒从我的 Angular 应用程序中的 Web api 轮询一次数据。这导致我的角材质扩展面板返回到未扩展的默认位置并减慢网站速度,从而给用户带来不便。如果我用于更新视图的数据与视图的当前数据不同,我是否可以只更新视图?

下面是我的组件的代码。

              //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>

在我的 component.ts 中,我使用 ngrx store 从 web api 获取我的数据。 vehicleDetail 是选定的车辆,而 vehicleDetail?.histalarm" 用于循环遍历车辆存在的警报列表。


// component.ts
ngOnInit() {
   // init vehicles details
    this.store.select(fromStore.getAllVehicleDetails).subscribe(data => {
      this.vehicleDetails = data;
      this.setMarkers(this.selected);
      this.updateFavoriteVehicles();
    });
    this.store.dispatch(new fromStore.LoadVehicleDetails());
}

目前我最担心的是,当用户尝试阅读详细信息时,扩展面板会不断更新。发生这种情况是因为我告诉扩展面板每 15 秒更新一次,因为我希望更新时间戳和其他内容。然而,不断的中断令人沮丧,这就是我想要解决的问题。

编辑

发布reducer的代码以及请求

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;

【问题讨论】:

  • 能看一下组件代码吗?
  • 能否提供相关代码以便我们在这里为您提供帮助?
  • 感谢您的回复@Raph 和 CruelEngine,它已更新。如果您希望我发布更多相关代码,请告诉我。
  • 你试过 distinctUntilChanged 运算符吗?检查这个link。它可能会有所帮助
  • 您能否发布您的 NGRX reducer 代码,该代码将从 API 接收到的数据更新为状态?

标签: javascript angular typescript asp.net-web-api ngrx


【解决方案1】:

您遇到的问题是每次刷新数据时您都在替换状态中的对象。这意味着 NGRX 将通知任何订阅者选择该对象已更改,这意味着 Angular 将重新绘制 UI,因为 observable 已发出。

为了避免额外的重新绘制,您需要做的是在您的减速器中评估细节是否已更改,然后仅在细节已更改时才返回更新状态。要计算细节是否发生变化,您需要对从 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 函数来评估新旧实体是否相同。 lodash have operators for doing this 之类的库,或者您可以编写自己的特定检查,了解刷新时可能更改的属性和内容。

【讨论】:

  • 非常感谢您的回复!时间戳将始终更新,因此每个对象都将与前一个对象不同。我有办法解决这个问题吗?因为我想不断更新时间戳。或者这是不可能的,因为这两个属性属于同一个对象?
  • 如果您希望在显示时更新时间戳,显然您必须更新对象并且无法避免重绘。如果您不关心时间戳,则可以在进行 reduce 时将其从 vehicledetail 对象中删除(例如,delete vehicledetail.timestampreduce 回调中的返回行之前)。
  • 另一个选项是将“最后更新的时间戳”分解到不同的树中并单独选择它,因此如果时间戳发生变化但其他细节没有变化,您可以为细节。 @maac
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-11
  • 2012-06-15
  • 1970-01-01
  • 1970-01-01
  • 2021-03-30
  • 2018-12-30
  • 1970-01-01
相关资源
最近更新 更多