考虑代码:
import React, { useState, useEffect } from 'react';
........ More stuff
const ProductContext = React.createContext();
const ProductConsumer = ProductContext.Consumer;
const ProductProvider = ({ children }) => {
const [state, setState] = useState({
sideBarOpen: false,
cartOpen: true,
cartItems: 10,
links: linkData,
socialIcons: socialData,
cart: [],
cartSubTotal: 0,
cartTax: 0,
cartTotal: 0,
.......
loading: true,
cartCounter: 0,
});
const getTotals = () => {
// .. Do some calculations ....
return {
cartItems,
subTotal,
tax,
total,
};
};
const addTotals = () => {
const totals = getTotals();
setState({
...state,
cartItems: totals.cartItems,
cartSubTotal: totals.subTotal,
cartTax: totals.tax,
cartTotal: totals.total,
});
};
/**
* Use Effect only when cart has been changed
*/
useEffect(() => {
if (state.cartCounter > 0) {
addTotals();
syncStorage();
openCart();
}
}, [state.cartCounter]);
..... More code
return (
<ProductContext.Provider
value={{
...state,
............... More stuff
}}
>
{children}
</ProductContext.Provider>
);
};
export { ProductProvider, ProductConsumer };
这是购物车的上下文,无论用户何时向购物车中添加新商品 这段代码运行:
useEffect(() => {
if (state.cartCounter > 0) {
addTotals();
syncStorage();
openCart();
}
}, [state.cartCounter]);
并更新状态,但是setState
函数不会更新state
运行时:
setState({
...state,
cartItems: totals.cartItems,
cartSubTotal: totals.subTotal,
cartTax: totals.tax,
cartTotal: totals.total,
});
在addTotals
内部,即使UseEffect检测到state.cartCounter
已更改时也会自动调用此函数。
为什么更改没有反映在state
变量中?
答案 0 :(得分:1)
没有精简的工作示例,我只能猜测问题所在……
您正在useEffect
中调用一个回调函数,应将该回调函数添加到[dependencies]
中以进行记忆。
const dep2 = React.useCallback(() => {}, []);
useEffect(() => {
if(dep1 > 0) {
dep2();
}
}, [dep1, dep2]);
由于dep2
是一个回调函数,如果未将其包装在React.useCallback
中,则更改后可能会导致无限次重新渲染。
您正在突变状态对象或其属性之一。由于我没有看到完整的代码,因此这只是一个假设。但是Array方法,例如:splice
,push
,unshift
,shift
,pop
,sort
,仅举几例引起了原始Array的突变。另外,可以使用delete prop
或obj.name = "example"
或obj["total"] = 2
对对象进行突变。同样,没有完整的代码,这只是一个猜测。
您试图在执行时传播陈旧状态。当使用多个setState
调用来更新对象时,不能保证state
在执行时将是最新的。最佳实践是向setState传递一个函数,该函数接受当前状态作为参数并返回更新的状态对象:
setState(prevState => ({
...prevState,
prop1: prevState.prop1 + 1
}));
这可确保在批量执行状态时始终保持最新状态。例如,如果第一个setState更新cartTotal: 11
,那么在执行下一个setState时,保证prevState.cartTotal
为11。
如果state.cartCounter
在此组件中进行过更新,则将导致无限的重新渲染循环,因为useEffect
会在每次更改时监听并触发。 在您的项目中这可能是问题,也可能不是问题,但这是需要注意的。一种解决方法是触发一个布尔值,以防止addTotals
执行多次。由于道具名称“ cartCounter”是一个数字,并且与其整体功能模棱两可,因此,这不是同步更新购物车总数的最佳方法。
React.useEffect(() => {
if (state.cartCounter > 0 && state.updateCart) {
addTotals();
...etc
}
}, [state.updateCart, state.cartCounter, addTotals]);
正在运行的演示(点击Add to Cart
按钮以更新购物车状态):
如果上述任何一个问题都不能解决您的问题,那么建议您创建一个mwe。否则,这是一个猜谜游戏。