用重选计算状态数据

时间:2018-04-18 10:08:45

标签: javascript react-redux reselect

我的React Web应用程序的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秒获取一次数据并将其作为有效负载传递(以及有关更新内容的信息,例如,每天。提供)。 每次按照redux指南调用时,该操作都会创建整个状态树的新副本。

然后我有一个显示数字的组件,作为这个状态总计的计算(我传递道具,如[" a"," b"],& #34;每月","提供"到组件,检索每月提供的总和) 这使用重新选择如下:

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}
    });
};

随着后台功能数量的增加(并且它们将会增加,因为将来我需要获取更多数据),这些选择器会被调用很多,并且webapp开始感觉越来越慢" #34 ;. 有没有办法优化这个选择器? (以及动作/状态树?)

1 个答案:

答案 0 :(得分:0)

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

这是因为reselect缓存在新值和以前传递的值之间执行严格的相等比较(===)检查,并且JS通过引用比较对象/数组。

如果你想让两个getter都返回一个数组,你需要确保它们在使用相同的输入调用时返回相同的数组。类似的东西:

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应该能够提供至少初始级别的数据存储。