Redux + Reselect:防止在 GPS 数据更新时重新计算选择器

Redux + Reselect: Preventing selector recalculation when GPS data updates

最近,我一直在开发一个非常大的应用程序,使用 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 或名称发生变化时才从数据库中推送更改,但这是我希望远离的解决方案,因为它会导致许多相同的数据要在商店中多次存储。

我尝试了以下方法:

如果有人需要更多信息或说明,请随时询问。

更新:这是一个问题的主要原因之一是对任何狗的任何 GPS 更新都会导致 dogDataSelector return 一个新的参考。反过来,这将导致 animalsSelector 触发更新并 return 一个新值。

注意:由于评论中详述的原因,这将不起作用

如果你不需要gps数据,那你当然可以把它去掉,reselect会忽略它

类似于:

const dogDataSelector = state => state.data.dogs;

const animalsSelector = createSelector(
    dogDataSelector,
    (dogs) => {
        return Object.keys(dogs).map(id => {
            return dogs[id];
        })
    },
    (dogsArray) => dogsArray.map(({id, name}) => ({id, name}))
)

immutable 数据更新的标准方法要求,如果更新嵌套字段,则也应复制和更新树中的所有祖先。在您的示例中,对 dog[3].gps 的更新将需要对 gps 数组、dog[3]dogsdata 的新引用。因此,使用此数据结构,对 gps 字段 的任何更新都必须 导致整个链上的新引用,因此 UI 将查看新引用并假设它需要重新渲染。

一些可能的建议:

  • 编写一个选择器,通过它的 ID 查找狗条目,去掉 gps 字段,然后对先前的值进行某种浅层相等性检查,看看是否有非 gps 字段实际上已经更改,因此只有当其中一个字段不同时才会返回新的 "dog entry minus gps" 对象。
  • 将 GPS 值存储在单独的查找 table 中,以 ID 为键,而不是嵌套在狗条目本身中,这样更新 GPS 数组就不会产生新的狗条目引用。