如何避免在调度新操作时通过循环访问存储对象而重新呈现组件



很抱歉标题令人困惑,但问题很难如此简短地描述。我有一个连接到 WebSocket API 并将新数据调度到 NgRx 存储的服务,如下所示:

this.priceSocket.subscribe(
message => this.handleMessage(message),
error => console.log(error),
() => console.log("completed")
)

这是我将消息传递给的handleMessage()函数:

handleMessage(message) {
if (message.price) {
this.store.dispatch({type: "PRICES", payload: {product_id: message.product_id, price: message.price}})
}
}

这是我非常简单的减速器:

export function priceReducer(state: object = {prices: {}}, action: Action) {
switch (action.type) {
case "PRICES":
return {...state, prices: {...state.prices, [action.payload.product_id]: action.payload.price}};
}
}

然后,在我的一个组件中,我对商店中的数据切片使用.pipe(share()),使用| async管道将其传递给模板,并循环通过它为 price 对象中的每个属性呈现一个子组件:

prices = this.store.select(state => state.message ? state.message.prices : null).pipe(share());

和模板:

<div class="card-wrapper">
<app-price *ngFor="let item of prices | async | keyvalue" [priceKey]="item?.key" [priceValue]="item?.value"></app-price>
</div>

这是有效的,因为它实时显示子组件中的数据,但是我发现的问题是,每次新数据来自 WebSocket 并发送到存储时,所有子组件都会重新呈现。我认为这是因为每次调度新操作时都会重建存储,因此*NgFor再次循环整个新对象并重新渲染每个子组件。

我设法通过对同一数据切片使用.subscribe()来避免这种行为,从组件本身中的数据构建一个新对象,该对象对我要显示的每个实时值都有一个新BehaviorSubject。然后,我将对象传递给模板,并对对象中的每个单独值而不是整个对象使用| async。这样我就可以得到预期的行为,这只是相关的子组件重新渲染,而不是所有子组件。我想知道是否可以在不使此对象在组件中生成此对象而是将数据直接从存储传递到模板的情况下实现相同的行为。

使用ngFor时,也可以使用ngForTrackBy

定义如何跟踪可迭代对象中项的更改的函数。

在可迭代对象中添加、移动或删除项时,指令必须重新呈现相应的 DOM 节点。为了最大程度地减少 DOM 中的改动,仅重新呈现已更改的节点

默认情况下,更改检测器假定对象实例标识可迭代对象中的节点。提供此函数时,指令使用调用此函数的结果来标识项节点,而不是对象本身的标识。

该函数接收两个输入,即迭代索引和节点对象 ID。

参考: https://angular.io/api/common/NgForOf

最新更新