【发布时间】:2018-06-14 16:06:16
【问题描述】:
最近,我一直在开发一个非常大的应用程序,使用 React+Redux 和 Reselect 来记忆数据并防止不必要的重新渲染,我遇到了一个我似乎无法解决的特定问题。
在 Redux 状态下,我将大量数据存储为由 id 索引的对象。这些对象都有一个属性(我们称之为 gps),它会随着实时 gps 坐标进行更新。
这些数据有两种用途。第一个是在地图上,其中 GPS 数据是相关的。第二个是在 UI 中,其中 GPS 数据不相关。任何时候更新任何对象的 GPS 数据时,该对象都会流入并在 Redux 存储中替换,这会更新我的选择器中该对象的引用。
Redux 存储示例:
data: {
dogs: {
1: {id: 1, name: "name1", gps: [123, 234]},
2: {id: 2, name: "name2", gps: [123, 234]},
3: {id: 3, name: "name3", gps: [123, 234]},
4: {id: 4, name: "name4", gps: [123, 234]}
}
}
例如 state.dogs[1].gps 中的数据可能每秒更新 3 到 5 次。这可能发生在 state.data.dogs 中的任何对象中。
选择器的写法如下:
const dogDataSelector = state => state.data.dogs;
const animalsSelector = createSelector(
dogDataSelector,
(dogs) => {
return Object.keys(dogs).map(id => {
return dogs[id];
})
}
)
现在,当我想要所有狗时,这段代码可以正常工作,因为它们会更新,包括 GPS。
我似乎无法弄清楚如何专门为不包括 GPS 更新的 UI 编写选择器。 100次中有99次,当狗更新时,它是GPS更新。 UI 根本不关心 GPS,但正因为如此,选择器会向前发送新数据,这会导致 UI 重新渲染。
我知道可以编写一个新流,仅在狗的 id 或名称更改时才从数据库推送更改,但这是我希望远离的解决方案,因为它会导致很多相同的数据要在存储中多次存储。
我尝试了以下方法:
- 创建一个选择器,该选择器返回一个精简版的狗,只有 id 和 name,通过键存储在一个对象中。此选择器稍后用作输入选择器,但仍会导致不必要的选择器返回。
- 创建一个只返回一组狗 ID 的选择器,并将其传递给 UI。深度相等检查用于防止重新渲染,id 数组用于从状态中提取特定的狗对象。这不是一个理想的解决方案,而且看起来很糟糕。
如果有人需要更多信息或说明,请随时提问。
更新:这是一个问题的主要原因之一是任何狗的任何 GPS 更新都会导致 dogDataSelector 返回一个新的参考。反过来,这将导致 animalsSelector 触发更新并返回一个新值。
【问题讨论】:
-
我认为解决方案是自定义相等检查,使用
createSelectorCreator- 请参阅github.com/reduxjs/… -
@DavidKemp 这是我尝试过的一种解决方案,以及它目前的实施方式。它可以工作,但可能会更好,因为通过的数据量可以是 5000 多个项目,并且在这一点上,额外的渲染似乎比相等检查更便宜。不过,谢谢你的帮助!如果我不能实施更好的解决方案,这就是我将要采用的方法。
标签: reactjs data-structures redux reselect