使用重新选择计算状态数据

Computing state data with reselect

我的 React 网络应用程序的 redux 状态分支结构如下:

  a: {
    daily: {
      offers: {
        total: 0,
        data: []
      },
      typ: {
        total: 0,
        data: []
      }
    },
    monthly: {
      offers: {
        total: 0,
        data: []
      },
      typ: {
        total: 0,
        data: []
      }
    }
  },
  b: same structure, c:same structure and so on

整个状态通过一个动作更新,由不同的函数调用(大约 10 个 运行 异步的函数)每 30 秒获取一次数据并将其作为有效载荷传递(连同关于什么的信息更新,例如 b.daily.offers)。 每次按照 redux 指南调用时,该操作都会创建整个状态树的新副本。

然后我有一个显示数字的组件,作为该州总计的计算(我传递像 ["a"、"b"]、"monthly"、[=23 这样的道具=] 到组件,以检索每月报价总额的总和) 这使用重新选择如下:

import {createSelector} from 'reselect'

const getGroup= (_, props) => {
  switch (props.group) {
    case "all":
      return ["a", "b", "c"];
    default:
      return props.group;
  }
};
const getTimespan = (_, props) => {
  switch (props.timespan) {
    case "daily":
      return ["daily"];
    case "monthly":
      return ["daily", "monthly"];
  }
};
const getPage = (_, props) => props.page;
const getA = (state) => state.a;
const getC = (state) => state.b;
const getB = (state) => state.c;

export const makeGetStatistic = () => {
  return createSelector(
    [getA, getB, getC, getPage, getGroup, getTimespan],
    (a, b, c, page, group, timespan) => {
      let o = 0;
      let data = {
        "a": a,
        "b": b,
        "c": c
      };
      group.forEach((device) => {
        timespan.forEach((time) => {
          o += data[device][time][page].total;
        })
      })
      return {data: o}
    });
};

随着后台函数越来越多(而且还会越来越多,因为以后我需要取更多的数据),这些selector被调用的越来越多,webapp越来越有感觉了"slow". 有没有办法优化这个选择器? (还有 actions/state 树?)

我在这里看到的第一个问题是 getGroupgetTimespan 总是 return 一个新数组 ,使 makeGetStatistic 无效任何单个调用的选择器缓存。

发生这种情况是因为reselect缓存在新的和以前传递的值之间执行严格的相等比较(===)检查,并且JS通过引用比较objects/arrays。

如果你想保留两个 getter return 一个数组,你需要确保它们 return 在使用相同的输入调用时使用相同的数组.类似于:

const ALL_GROUPS = ["a", "b", "c"];
const getGroup= (_, props) => {
  switch (props.group) {
    case "all":
      return ALL_GROUPS;
    default:
      return props.group;
  }
};

const DAILY_TIMESPAN = ["daily"];
const MONTHLY_TIMESPAN = ["daily", "monthly"];
const getTimespan = (_, props) => {
  switch (props.timespan) {
    case "daily":
      return DAILY_TIMESPAN;
    case "monthly":
      return MONTHLY_TIMESPAN;
  }
};

这样 reselect 应该能够在使用相同输入调用时至少提供初始级别的数据记忆。