重新选择-创建一个只用于获取部分状态的记忆选择器有意义吗



我有一个普通的选择器,它只用于获取部分状态:

export const getAllPosts = state => {
return state.posts;
};

如果我使用重新选择来包装选择器:

import { createSelector } from 'reselect';
export const allPosts = createSelector(
getAllPosts,
(posts) => posts
);

这有什么意义吗,比如提高性能?在我看来,包装是不必要的。

不,仅仅为了获得状态树的一部分而创建一个内存化选择器是没有意义的。

原因是connect将对从mapStateToProps传入的每个道具进行自己的浅相等检查。如果选择器返回的prop与其他prop一起通过了浅相等检查,则不会不必要地调用render。如果选择器只是返回了状态树的一部分,而状态树的这部分没有被修改,那么简单的相等性检查就足够了。

但是,如果选择器是根据其他选择器的结果计算的,那么使用createSelector是一个不错的选择。首先,它为编写选择器提供了一个很好的语法。其次,如果组合选择器的计算可能很昂贵,那么您将获得性能优势。第三,如果选择器要返回一个新的但等价的对象或数组,那么connect提供的浅相等检查是不够的。在这种情况下,createSelector提供的记忆将确保在输入没有改变的情况下返回相同的对象或数组实例,然后浅相等性检查将足以避免代价高昂的重新渲染。

因此,仅公开状态树的一部分createSelector不会添加任何内容。

对于从状态树的多个部分计算的几乎所有选择器,createSelector开始添加值。它添加的值的数量因选择器而异,从更容易读取到确保不会不必要地重新渲染组件树。

在您的情况下,这是没有意义的,因为您只是从存储中返回相同的引用,该引用总是浅等于它自己(或它以前的状态),除非您修改它。

如果你想象一个不同的场景,例如,你将实体存储在一个对象中,而不是存储中的数组,但你想将数组返回给你的组件,那么你需要导出数据:

export const selectAllPosts = createSelector(
getAllPostsFromStore, // returns { 1: {...}, 2: {...} }
(allPosts) => Object.keys(allPosts).map(key => allPosts[key])
);

现在,您的选择器变成了性能提升,因为它只在存储中的某些内容发生更改时计算派生数据。

所以我的经验法则是:如果你不导出数据,你就不需要记忆它

不,这不会带来真正的好处。

我发现,我的一级选择器只是简单的函数,任何比它更深的选择器都需要记忆:

// assume state is:  {first : {second {} } }
const selectFirst = state => state.first;
const selectSecond = createSelector(
selectFirst,
first => first.second
);

最新更新