记住派生数据
在你的 redux 商店中,你可以保存原始数据。有时原始数据就是你所需要的,但有时你需要从原始数据中获取新数据,通常是通过组合部分原始数据。
用于导出数据的常见用例是基于标准过滤数据列表,其中列表和标准都可以被改变。
以下示例实现 mapStateToProps 并过滤字符串列表以保留与搜索字符串匹配的字符串,从而生成可由 React 组件呈现的新 prop filteredStringList
。
// Example without memoized selectors
const mapStateToProps(state) => {
const {stringList, searchString} = state;
return {
filteredStringList: stringList
.filter(string => string.indexOf(searchString) > -1)
};
}
为了简化 Reducer,你应该只保存商店中的数据列表和过滤条件,这意味着你需要在读取时间内获取数据(就像我们在上面的示例中所做的那样)。
获取有关读取时间的数据会带来两个问题:
- 如果多次导出相同的数据,则可能会影响性能。
- 如果不同组件中需要相同的数据,你可能会发现要复制代码以获取数据。
解决方案是使用仅定义一次的 memoized 选择器。React 社区建议使用 npm 库重新选择来创建 memoized 选择器。在下面的示例中,我们获得与第一个示例中相同的结果,仅使用 memoized 选择器。
// Create memoized selector for filteredStringList
import {createSelector} from 'reselect';
const getStringList = state => state.stringList;
const getSearchString = state => state.searchString;
const getFilteredStringList = createSelector(
getStringList,
getSearchString,
(stringList, searchString) => stringList
.filter(string => string.indexOf(searchString) > -1)
);
// Use the memoized selector in mapStateToProps
const mapStateToProps(state) => {
return {
filteredStringList: getStringList(state)
};
}
请注意,两个第一选择器 getStringList
和 getSearchString
没有被记忆,因为它们非常简单,不会提供任何性能提升。它们仍然需要创建,因为我们需要将它们作为依赖项传递给 createSelector
,以便它知道何时重用 memoized 结果以及何时计算新结果。
memoized 选择器将使用传递给 createSelector
的最后一个参数传递的函数来计算派生数据(在我们的示例中,返回过滤后的字符串列表的函数)。每次调用 memoized 选择器时,如果从上次调用依赖项后没有更改(在我们的示例中 stringList
和 searchString
),memoized 选择器将返回先前的结果,从而节省重新计算它的时间。
你可以将选择器(memoized 或 not memoized)视为商店状态的 getter,就像 action-creators 是 setter 一样。
你可以在 Redux 文档的配方部分找到有关计算派生数据的更多示例。