将全局变量的地址作为传参_双刃剑--全局变量

f46ecc77b6dbf1a0dae4f1fa8c182ef9.png

让我注意到这个问题,是最近遇到了一需求:需要将一个对象数组的相同属性累加起来,计算出总计值。

e4db9323422efd1442f2e57940235367.png
期望的结果

代码如下:

/**
 * arr 数据源对象, init 初始值
 */
function cumulative(arr: any, init: any) {
  return arr.reduce((acc: any, cur: any) => {
    Object.keys(acc)
      .forEach(i => (acc[i] += cur[i]));
    return acc;
  }, init);
}

const totalTem = {
  yearMonth: '总计',
  offlineSaleQuantity: 0,
  onlineSaleQuantity: 0,
  salesRatio: 0,
};

const Details: React.SFC<IDetailProps> = _store => {
  const { detailList } = _store;
  const [final, setFinal] = useState([]);
  useEffect(() => {
    // 累加每一项,计算总计值
    const total = cumulative(detailList, totalTem);
    // 合并数据
    setFinal([...detailList, total]);
  }, [detailList]);
  return (
    <DetailTable loading={loading[`${NS}/fetchList`]} detailList={final} />
  );
};

这个时候出现了一个bug,当我每次重新请求到新数据时,总计值都会将上一次的累加结果作为初始值,而不是使用代码里的初始值。这个时候可以断定:之前的数据被缓存了!

因为在cumulative方法中传入totalTem作为init(也是reduce中acc第一次的值),累加操作都是在acc上进行,acc与totalTem指向同一个引用地址,也就是同一个对象。所以每次计算之后totalTem会被改变,而它是一个全局变量(只会在js文件重载时重置),组件更新不会影响它

解决方案有两种

  1. 在组件内部定义totalTem,当组件更新时会重置它
  2. 另一种是拷贝totalTem,隔离引用关系(这里用的是浅拷贝,因为totalTem只有一层)
const totalTemCopy = { ...totalTem };
...
const total = cumulative(detailList, totalTemCopy);

拓展

全局变量特点是不跟随组件生命周期而更新。虽然我这里不需要用到全局缓存,但是我们可以考虑一些他的应用场景。

比如,在我们项目中使用dva做状态管理,一般将逻辑写在model.js中,然而业务一旦复杂,代码量会很大造成文件冗余。所以我们将逻辑单独抽离到logic.js文件中,model.js只负责处理同步异步、数据存储操作。

fef5b60ac0aafe6e78422119a391e74b.png

logic.js中需要调用dispatch与model通信,这里就需要用到全局变量。在页面初始化时需要将dispatch作为全局变量缓存在logic.js中。

以上,如有勘误,欢迎指正: )

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值