[英]UseState called by UseEffect doesn't update the variable using the Set method
Consider the code :考虑代码:
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 };
This is a Context of a Shopping cart ,whenever the user add a new item to the cart this piece of code runs :这是购物车的上下文,每当用户向购物车添加新项目时,这段代码就会运行:
useEffect(() => {
if (state.cartCounter > 0) {
addTotals();
syncStorage();
openCart();
}
}, [state.cartCounter]);
And updates the state , however the setState
function doesn't update state
when running :并更新 state ,但是setState
函数在运行时不会更新state
:
setState({
...state,
cartItems: totals.cartItems,
cartSubTotal: totals.subTotal,
cartTax: totals.tax,
cartTotal: totals.total,
});
Inside addTotals
, even though this function is being called automatically when UseEffect detects that state.cartCounter
has been changed.在addTotals
,即使当 UseEffect 检测到state.cartCounter
已更改时会自动调用此函数。
Why aren't the changes being reflected in the state
variable ?为什么更改没有反映在state
变量中?
Without a stripped down working example, I can only guess at the problems...没有精简的工作示例,我只能猜测问题......
You're calling a callback function in useEffect
which should be added to it's [dependencies]
for memoization.您正在调用useEffect
的回调函数,应将其添加到它的[dependencies]
以进行记忆。
const dep2 = React.useCallback(() => {}, []);
useEffect(() => {
if(dep1 > 0) {
dep2();
}
}, [dep1, dep2]);
Since dep2
is a callback function, if it's not wrapped in a React.useCallback
, then it could potentially cause an infinite re-render if it's changed.由于dep2
是一个回调函数,如果它没有包含在React.useCallback
,那么如果它被更改,它可能会导致无限重新渲染。
You're mutating the state object or one of its properties.您正在改变状态对象或其属性之一。 Since I'm not seeing the full code, this is only an assumption.由于我没有看到完整的代码,这只是一个假设。 But Array methods like: splice
, push
, unshift
, shift
, pop
, sort
to name a few cause mutations to the original Array.但是 Array 方法如: splice
、 push
、 unshift
、 shift
、 pop
、 sort
仅举几例会导致原始 Array 发生突变。 In addition, objects can be mutated by using delete prop
or obj.name = "example"
or obj["total"] = 2
.此外,可以使用delete prop
或obj.name = "example"
或obj["total"] = 2
。 Again, without the full code, it's just a guess.同样,没有完整的代码,这只是一个猜测。
You're attempting to spread stale state when it's executed.您试图在执行时传播陈旧状态。 When using multiple setState
calls to update an object, there's no guarantee that the state
is going to be up-to-date when it's executed.当使用多个setState
调用来更新一个对象时,不能保证state
在执行时是最新的。 Best practice is to pass setState a function which accepts the current state as an argument and returns an updated state object:最佳实践是向 setState 传递一个函数,该函数接受当前状态作为参数并返回更新的状态对象:
setState(prevState => ({
...prevState,
prop1: prevState.prop1 + 1
}));
This ensures the state is always up-to-date when it's being batch executed.这确保状态在批处理执行时始终是最新的。 For example, if the first setState updates cartTotal: 11
, then prevState.cartTotal
is guaranteed to be 11 when the next setState is executed.例如,如果第一个 setState 更新了cartTotal: 11
,那么在执行下一个 setState 时, prevState.cartTotal
保证为 11 。
If state.cartCounter
is ever updated within this component, then this will cause an infinite re-render loop because the useEffect
listens and fires every time it changes.如果state.cartCounter
在这个组件中被更新,那么这将导致无限重新渲染循环,因为useEffect
每次更改时都会监听并触发。 This may or may not be a problem within your project , but it's something to be aware of.这在您的项目中可能是也可能不是问题,但这是需要注意的。 A workaround is to trigger a boolean to prevent addTotals
from executing more than once.解决方法是触发布尔值以防止addTotals
执行多次。 Since the prop name "cartCounter" is a number and is rather ambiguous to its overall functionality, then it may not be the best way to update the cart totals synchronously.由于道具名称“cartCounter”是一个数字并且对其整体功能相当模糊,因此它可能不是同步更新购物车总数的最佳方式。
React.useEffect(() => {
if (state.cartCounter > 0 && state.updateCart) {
addTotals();
...etc
}
}, [state.updateCart, state.cartCounter, addTotals]);
Working demo (click the Add to Cart
button to update cart state):工作演示(单击Add to Cart
按钮以更新购物车状态):
If neither of the problems mentioned above solves your problem, then I'd recommend creating a mwe .如果上述问题都不能解决您的问题,那么我建议您创建一个mwe 。 Otherwise, it's a guessing game.否则就是猜谜游戏。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.