I'm trying to add items in shopping cart. It works, but after adding items when I want to calculate number of items to show on the shopping cart. Second function (calculate()) doesn't wait items hooks. Because of that, it shows the correct count after adding second item.
Below code is my functions. As you can see, in the end of first function I'm calling the calculate() function to keep it continue.
const [testArray, setTestArray] = useState([]);
const [total, setTotal] = useState(0);
const [cartCount, setCartCount] = useState(0);
function addToTest(product, quantity = 1) {
const ProductExist = testArray.find((item) => item.id === product.id);
if (ProductExist) {
setTestArray(
testArray.map((item) => {
if (item.id === product.id) {
return { ...ProductExist, quantity: ProductExist.quantity 1 };
} else {
return item;
}
})
);
} else {
product.quantity = 1;
setTestArray([...testArray, product]);
}
calculate();
}
function calculate() {
let resultCount = 0;
testArray.map((item) => {
console.log("map func works!");
setCartCount(cartCount item.quantity);
});
}
Here is my codesandbox project, I kept it very simple to not bother you.
https://codesandbox.io/s/react-template-forked-u95qt?file=/src/App.js
The possible problem occurs due to synchronise functions. Because of that, when I try to async/await, I'm getting error about parameters, because the first function has parameter.
This is my first try for async/await:
async function calculate(product) {
await addToTest(product);
let resultCount = 0;
testArray.map((item) => {
console.log("map func works!");
setCartCount(cartCount item.quantity);
});
}
As other solution I tried to use useEffect by taking the reference setArray hooks. However, in this case, the count number increases exponentially like 1,3,9...
useEffect(()=>{
let resultCount = 0;
testArray.map((item) => {
console.log("map func works!");
setCartCount(cartCount item.quantity);
});
},[testArray])
I wonder where is the problem? Because when I use the the upper code in Angular/Typescript, it works properly. I think this happens due to react hooks, but I couldn't understand the problem.
CodePudding user response:
Every call to setCartCount
will only update cartCount
on the next render, so you are (effectively) only calling it with the final item in the array. You should instead use reduce
on the array to get the value you want, and then set it.
See https://codesandbox.io/s/react-template-forked-u95qt?file=/src/App.js
CodePudding user response:
Your thought to use a useEffect
is a good one, but instead of calling setCartCount
on every iteration you should instead sum all the item.quantity
counts first and then call setCartCount
once after your loop.
Note: don't use map()
if you're going to ignore the array it returns, use a for
loop, for...of
as in the example below, or forEach()
instead.
useEffect(() => {
let resultCount = 0;
for (const item of testArray) {
resultCount = item.quantity;
}
setCartCount(resultCount);
}, [testArray]);
or with reduce()
(here destructuring and renaming the quantity
property of each passed item
)
useEffect(() => {
const resultCount = testArray.reduce((a, { quantity: q }) => a q, 0);
setCartCount(resultCount);
}, [testArray]);