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 :
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.
Why aren't the changes being reflected in the state
variable ?
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.
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.
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. In addition, objects can be mutated by using delete prop
or obj.name = "example"
or 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. Best practice is to pass setState a function which accepts the current state as an argument and returns an updated state object:
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.
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. 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. 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.
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):
If neither of the problems mentioned above solves your problem, then I'd recommend creating a mwe . Otherwise, it's a guessing game.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.