React 中 useEffect 钩子函数可以简单理解为 componentDidMount 和 componentUpdateMount 结合体,使用起来是相当的舒爽。因为可以通过检测内存中变量的地址的变化,来执行副作用代码。
但是需要注意的是, useEffect 监听的是变量在内存中的地址引用,如果变量引用没有发生变化,他是监听不到的,副作用代码并不会触发执行。
很常用的场景就是,我们在做购物车要通过商品的数量变化动态计算合计金额。
实现代码:
useEffect(() => {
let selectedTotalCoin = 0;
checkedItemList && checkedItemList.map(item => {
selectedTotalCoin += item['selectedQty'] * item['cartItem']['itemDiscountPrice']
})
setTotalCoin(selectedTotalCoin)
}, [checkedItemList])
const handleSelectItem = (clickedItem, isChecked, qty, isOnlyUpdateQty) => {
clickedItem['selectedQty'] = qty
if (isChecked) {
if (isOnlyUpdateQty) {
checkedItemList.map(item => {
if (item['cartItemId'] === clickedItem['cartItemId']) {
item['selectedQty'] = qty
}
return item
})
setCheckedItemList(checkedItemList) // 问题代码
} else {
setCheckedItemList([...checkedItemList, clickedItem])
}
} else {
let newCheckedItemList = []
for (let key in checkedItemList) {
let cartItem = checkedItemList[key]
if (cartItem['cartItemId'] !== clickedItem['cartItemId']) {
newCheckedItemList.push(cartItem)
}
}
setCheckedItemList(newCheckedItemList)
}
}
这里面合计有两个逻辑,第一个是先确定金额后点击 checkbox 选中,计算出合计金额;第二个是对已经选中的商品增减数量,计算出合计金额;useEffect 钩子则是以 选中的商品checkedItemList来做监听,动态计算。
问题就出现在第二种情况, checkedItemList 的地址引用并未发生变化,map 中的直接赋值只是改变了其中一个item 的 qty,因此不会执行副作用代码,达不到动态计算的目的。
问题代码:
setCheckedItemList(checkedItemList) // 这其 checkedItemList 引用并未发生变化
修正后的代码:
//方法一:解构后重新生成数组
setCheckedItemList([...checkedItemList])
//方法二:构造新的变量
let newCheckedItemList = checkedItemList
setCheckedItemList(newCheckedItemList)