Как вложить селекторы повторного выбора?
у меня есть селектор, который возвращает массив. Сами элементы массива имеют производные данные. Мне по существу нужен рекурсивный селектор memoization, который возвращает производный массив, состоящий из производных элементов.
моя текущая попытка:
export const selectEntitesWithAssetBuffers = createSelector(
[selectSceneEntities, getAssets],
(entities, loadedAssets) => {
return entities.map((entity) => {
entity.buffers = entity.assets.map((assetName) => {
return loadedAssets[assetName].arrayBuffer;
})
return entity;
})
}
)
мои проблемы здесь в любое время entities
или loadedAssets
изменить это будет пересчитать весь список. То, что я ожидаю настроить, - это что-то вроде selectEntityWithBuffer
это будет передано в entities.map
. В идеале, я хочу этого только пересчитать, когда entity.assets
изменения массива.
3 ответов
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
не соответствует вашим потребностям.
в качестве доказательства концепции я бы попытался предоставить 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);
}
получение более глубокой memoization, чем то, что у вас есть, является сложной проблемой, потому что Reselect действительно не поддерживает передачу аргументов селекторам. Если вы возвращаете массив из селектора, и ввод, используемый для создания этого массива, изменился, это своего рода предполагаемое поведение от Reselect, которое вам нужно будет пересчитать. См.совет в readme для динамических аргументов.