angular - 如何避免在调度新操作时通过循环访问存储对象而重新渲染组件
问题描述
很抱歉标题令人困惑,但这个问题很难描述得这么简单。我有一个连接到 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
并循环通过它为价格对象中的每个属性呈现一个子组件:
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。
推荐阅读
- java - 检查带参数的方法是否有参数?
- javascript - 如何在 Laravel 或其他框架中正确编写表单?
- base64 - 如何将散景图转换为 BytesIO 对象以使用 base64 模块对图进行编码
- c# - XCEED PropertyGrid 可以接受结构吗?
- node.js - 通过angularjs上传文件对象文件但它被转换为字符串,如何在服务器端接收对象文件
- javascript - js函数看不到ng-repeat里面的元素
- python - 如何在 X_train、y_train、X_test、y_test 中拆分图像数据集?
- javascript - 在通过交换源的脚本后,单击按钮时需要 JavaScript 将图像源重置为原始
- windows - 检查是否存在带有批处理文件的 PostgresSQL DB 并将自定义值输出到文本文件
- ruby - 如何将 Launchy gem 用于数组?