![f46ecc77b6dbf1a0dae4f1fa8c182ef9.png](https://i-blog.csdnimg.cn/blog_migrate/4e23f83706ee66611bf57ebd09b3450c.jpeg)
让我注意到这个问题,是最近遇到了一需求:需要将一个对象数组的相同属性累加起来,计算出总计值。
![e4db9323422efd1442f2e57940235367.png](https://i-blog.csdnimg.cn/blog_migrate/ce59938c31c6a135185a36b11061a9fb.jpeg)
代码如下:
/**
* 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文件重载时重置),组件更新不会影响它
解决方案有两种
- 在组件内部定义totalTem,当组件更新时会重置它
- 另一种是拷贝totalTem,隔离引用关系(这里用的是浅拷贝,因为totalTem只有一层)
const totalTemCopy = { ...totalTem };
...
const total = cumulative(detailList, totalTemCopy);
拓展
全局变量特点是不跟随组件生命周期而更新。虽然我这里不需要用到全局缓存,但是我们可以考虑一些他的应用场景。
比如,在我们项目中使用dva做状态管理,一般将逻辑写在model.js中,然而业务一旦复杂,代码量会很大造成文件冗余。所以我们将逻辑单独抽离到logic.js文件中,model.js只负责处理同步异步、数据存储操作。
![fef5b60ac0aafe6e78422119a391e74b.png](https://i-blog.csdnimg.cn/blog_migrate/cd8123a5a6ab7eb9433d9f4adfda7c51.jpeg)
logic.js中需要调用dispatch与model通信,这里就需要用到全局变量。在页面初始化时需要将dispatch作为全局变量缓存在logic.js中。
以上,如有勘误,欢迎指正: )