记住派生数据

在你的 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,你应该只保存商店中的数据列表和过滤条件,这意味着你需要在读取时间内获取数据(就像我们在上面的示例中所做的那样)。

获取有关读取时间的数据会带来两个问题:

  1. 如果多次导出相同的数据,则可能会影响性能。
  2. 如果不同组件中需要相同的数据,你可能会发现要复制代码以获取数据。

解决方案是使用仅定义一次的 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)
    };
}

请注意,两个第一选择器 getStringListgetSearchString 没有被记忆,因为它们非常简单,不会提供任何性能提升。它们仍然需要创建,因为我们需要将它们作为依赖项传递给 createSelector,以便它知道何时重用 memoized 结果以及何时计算新结果。

memoized 选择器将使用传递给 createSelector 的最后一个参数传递的函数来计算派生数据(在我们的示例中,返回过滤后的字符串列表的函数)。每次调用 memoized 选择器时,如果从上次调用依赖项后没有更改(在我们的示例中 stringListsearchString),memoized 选择器将返回先前的结果,从而节省重新计算它的时间。

你可以将选择器(memoized 或 not memoized)视为商店状态的 getter,就像 action-creators 是 setter 一样。

你可以在 Redux 文档的配方部分找到有关计算派生数据的更多示例。