重新选择memoization忽略无关更新

时间:2016-12-22 15:28:06

标签: reactjs redux reselect

按照重新选择文档的示例:

import { createSelector } from 'reselect'

const shopItemsSelector = state => state.shop.items

const subtotalSelector = createSelector(
  shopItemsSelector,
  items => items.reduce((acc, item) => acc + item.value, 0)
)

在典型的redux应用中,subtotalSelector会在用户更新item.name时重新计算,即使这对结果没有影响。有没有办法避免这种情况?

2 个答案:

答案 0 :(得分:1)

两种解决方案:

  1. 好吧。除非您拥有大量项目,否则浏览器的计算能力足以处理重新计算。

  2. 从项目对象中分离价格。也就是说,您有state.shop.items.itemNames(包含id-name对)和state.shop.items.itemValues(包含id-value对)。然后只将itemValues传递给选择器。

答案 1 :(得分:0)

我有一个类似的问题,我发现了一种黑客攻击它。

我有一套复杂的过滤器,需要过滤大量的项目。过滤器状态的一部分包括显示状态。我想忽略显示状态的变化,所以我不会一直过滤大量的列​​表。这是一个简单的解决方案:

const getFilters = createSelector(
    state => state.filters,
    filters => {
        const filtersWithoutDisplay = {};
        const ignoreObj = { collapsed: null };
        for (let filterGroup in filters) {
            filtersWithoutDisplay[filterGroup] = Object.assign({}, filters[filterGroup], ignoreObj);
        }
        // We create a new object every time, so this cannot be memoized properly unless we stringify.
        return JSON.stringify(filtersWithoutDisplay);
    }
);

它返回一个必须被解析的JSON字符串,但是它是一个原语,因此如果实际内容没有改变,它就不会触发重新计算。那是一种黑客攻击。

您还可以在选择器函数之外定义一个对象,并始终保持相同的引用,根据相同的模式更改内部,然后通过引入createSelectorCreator使用自定义深度相等检查,如此处所述https://github.com/reactjs/reselect#q-why-is-my-selector-recomputing-when-the-input-state-stays-the-same。这可能是一个更好的方法,但正如它所说:

  

始终检查状态更新函数中替代equalityCheck函数或深度相等检查的成本是否不高于每次重新计算的成本。

这也适用于JSON.stringify hack。我不会为巨大的列表做这件事,但对于过滤器,肯定。

在我的情况下,重构我的状态可能更好,因为过滤器值可能与过滤器显示设置有关,这可能不是我希望它们分开的唯一时间。