如何嵌套Reselect选择器?

How to nest Reselect selectors?

我有一个 returns 数组的选择器。数组中的元素本身具有派生数据。我本质上需要一个递归记忆选择器 returns 一个由派生元素组成的派生数组。

我目前的尝试是:

export const selectEntitesWithAssetBuffers = createSelector(
  [selectSceneEntities, getAssets],
  (entities, loadedAssets) => {
    return entities.map((entity) => {
      entity.buffers = entity.assets.map((assetName) => {
        return loadedAssets[assetName].arrayBuffer;
      })
      return entity;
    })
  }
)

我担心的是随时 entitiesloadedAssets 更改这将重新计算整个列表。我期望设置的是类似于 selectEntityWithBuffer 的东西,它会传递给 entities.map。理想情况下,我希望它仅在 entity.assets 数组更改时才重新计算。

获得比现有内容更深的记忆是一个棘手的问题,因为 Reselect 并不真正支持将参数传递给选择器。如果您从选择器返回一个数组,并且用于构建该数组的输入已更改,那么您将需要重新计算 Reselect 的预期行为。有关动态参数,请参阅 the advice in the readme

作为概念证明,我会尝试通过绕过重新选择身份检查.

向结果函数提供 loadedAssets 对象
// Keep a private selector instance
let cachedSelector;

export const selectEntitesWithAssetBuffers = function(){
    // loadedAssets should be recalculated on each call?
    const loadedAssets = getAssets(arguments);

    // create selector on first call
    if(cachedSelector === undefined) {
        cachedSelector = createSelector(
            selectSceneEntities,
            entities => {
                return entities.map(entity => {
                    entity.buffers = entity.assets.map((assetName) => {
                        return loadedAssets[assetName].arrayBuffer;
                    })
                    return entity;
                })
            }
        )
    }

    // Return selector result
    return cachedSelector(arguments);
}

Reselect 允许您为选择器提供自定义相等性定义。

import { defaultMemoize, createSelectorCreator } from 'reselect'

const compareByAssets = (a, b) => {
    return a.every((element, index) => {
        return element.assets === b[index].assets
    });
};

const createAssetsComparatorSelector = createSelectorCreator(
    defaultMemoize,
    compareByAssets
);

const selectSceneEntitiesByAssetsComparator = createAssetsComparatorSelector((state) => {
    //however you normally get entities for the pre-existing selectors
});

现在您可以使用这个新的 selectSceneEntitiesByAssetsComparator 代替您提供的上述代码中之前的 selectSceneEntities 并且它只会重新 运行 当平等检查 compareByAssets 失败。

如果 assets === assets 的严格比较不符合您的需要,请随时进一步更新比较器功能。