使用 reselect 优化 Redux 中的性能问题

在进行前端开发过程中,处理大量数据的场景是非常常见的。在这种情况下,使用 Redux 管理应用的状态,是非常方便的一种解决方案。然而,我们会发现随着项目变得越来越庞大,性能问题也逐渐显现出来。这篇文章就将介绍如何使用 reselect 优化 Redux 中的性能问题。

Redux 与性能问题

在复杂的应用程序中,Redux 可能会被多个组件同时使用。每个组件都可能使用 Redux 存储中的相同部分数据。由于 Redux 是单一的数据存储,每个组件都会访问存储中的整个数据对象。这将导致对数据的多次不必要的传输以及不必要的计算。

为了避免这种问题,我们可以使用 reselect 库来提高 Redux 的性能。

什么是 reselect?

Reselect 是一个受 FP(函数式编程)启发的库,用于计算 Redux 存储中的衍生数据。Reselect 实际上是一个缓存库,它可以听取多个选择器函数,这些选择器函数负责从 Redux 存储中选择数据,并将这些数据用作输入来计算衍生数据。Reselect 缓存这些输入和输出,以便可以在下一次调用时快速计算衍生数据,而无需重新计算数据。

在具体实现中,我们需要编写选择器函数。这些选择器函数接受应用状态的参数,并返回衍生数据。选择器返回的结果将被缓存,以便可在下次使用中重复利用。

reselect 原理

Reselect 实现是基于以下原理:

  • 输入相同的参数将始终返回相同的输出

  • 与输入参数无关的组件状态将不会影响计算结果

在使用 Reselect 时,我们自定义选择器函数,从 Redux 存储中选取某些部分数据,并进行计算得到一些衍生数据。如果被选取的数据未发生变化,则不会重复计算该函数。这提高了应用的性能,因为在 Redux 存储中,只有真正发生变化的数据才会重新计算和更新。

如何使用 reselect?

使用 reselect 需要导入 createSelector 方法。createSelector 方法接受一组前置选择器,并返回一个接受 state 作为输入的新函数 (也叫做"组合选择器")。这个新函数取决于预先定义的选择器返回的值,并返回一个最终的汇总结果。

例如,假设 Redux 存储中有一个包含下列属性的数据对象

-
  ------ -
    - --- -- ----- ----- --- ---------- ---- --
    - --- -- ----- ----- --- ---------- ----- --
    - --- -- ----- ----- --- ---------- ----- --
    - --- -- ----- ----- --- ---------- ---- --
    - --- -- ----- ----- --- ---------- ----- -
  --
  ----------------- ----------------
-

我们可以创建一个选择器,该选择器返回"已完成"过滤器状态映射到"todos"数组的项

----- --------------- - ---------------
  ----- -- ------------
  ----- -- -----------------------
  ------- ----------------- -- -
    ------ ------------------ -
      ---- -----------------
        ------ ----------------- -- ---------------
      ---- --------------
        ------ ----------------- -- ----------------
      --------
        ------ -----
    -
  -
-

createSelector 接收多个函数作为参数,每个函数都接收 Redux 存储中的 state 作为参数并返回对象上的数据子集。在我们的示例中,我们传递了三个各自相互独立的函数,其中两个函数分别读取 Redux 存储中的 "todos" 和 "visibilityFilter"。第三个函数接收这两个值作为参数,然后根据 visibilityFilter 的值过滤 todos 数组,并返回一个新的 filteredTodos 组合对象。

现在,我们可以使用 getVisibleTodos 来获取过滤后的任务列表

----- --------------- - ----- -- --
  ------ ----------------------
--

示例代码

下面是一个使用 reselect 的示例代码,我们将从 state 中选取一部分信息并计算其衍生数据。

数据

我们的应用状态由以下数据对象组成。

-
  ------ -
    -- ---- -- ----- ------- ---- --- ---- --------
    -- ---- -- ----- ------- ---- --- ---- ----------
    -- ---- -- ----- ------ ---- --- ---- --------
    -- ---- -- ----- -------- ---- --- ---- ----------
  --
  ------- -----
-

其中,users 是一个对象,每个对象都是一个用户信息。filter 是一个字符串,可以是 "all" 或 "male" 或 "female"。

选择器函数

我们将编写三个选择器函数,分别取得用户信息、过滤条件和经过过滤的结果。

----- -------- - ----- -- -----------

----- --------- - ----- -- ------------

----- ---------------- - ---------------
  ---------- -----------
  ------- ------- -- -
    -- ------- --- ------ ------ --------------------
    ------ -------------------------------- -- -------- --- -------
  -
-

getFilteredUsers 接收两个参数,getUsersgetFilter 返回的数据子集。如果 filter 的值为 "all",则返回所有的 users,否则返回 sex 等于 filter 的 users。

组合选择器

我们将使用组合选择器将所有的选择器函数组合成一个新函数,在 mapStateToProps 中调用它来获取最新的经过过滤的用户列表。

----- --------------- - ----- -- --
  ------ -----------------------
--

总结

reselect 是一个优秀的库,它提供了计算衍生数据的技术,可以优化 Redux 中的性能问题。我们可以通过编写选择器函数并使用 createSelector 方法来缓存衍生数据,减少不必要的计算和传输,提高应用的性能。

同时,reselect 也能更好地使代码可读性更好,并且可以更清晰地表达对数据的过滤和转换操作。这对于长期维护和维护大型应用程序至关重要。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/66435e06d3423812e415e56e