user15779299
user15779299

Reputation: 81

setState not updating state after useEffect

I'm making a shopping cart app and I have a variable that loops through all prices and gets a total price of the cart. I am trying to have that total amount update the totals state through setTotals but while the total variable itself updates as items are removed from the cart, calling setTotals(total) does not update the state. It stays with the initial state on render (total price of all prices in cart).

my state declaration:

const [totals, setTotals] = useState()

getting the total from prices array:

 var total = 0
    for (var i = 0; i < prices.length; i++) {
        total += prices[i];
    }

calling setTotals in useEffect:

   useEffect(() => {
    setTotals(total) <-- From the loop above
    setCartCopy([...deepCartCopy])
}, [totals])

Can anyone please help?

Upvotes: 2

Views: 13764

Answers (2)

Bejita
Bejita

Reputation: 116

I think your approach of a card code is not the good one.

Here you always have the same information twice: you're getting the total in total and then you're setting totals with that same result. You can simplify by keeping only one of the two variables.

Also your code here is not working because the useEffect will never be executed: As you have put totals as a dependency, but it never changes. Even if you change totals somwhere else, you will have an infinite loop because in the useEffect depending on totals's changes, it change it value, which will execute the useEffect that changes totals etc etc, infinite loop.

I think your loop should also be in a useEffect with no dependencies as it will be executed only at the first render.

I would do soemthing like that, and maybe the code can be move improved:

  const [prices, setPrices] = useState([1, 3, 6, 39, 5]);
  const [total, setTotal] = useState(0);

  useEffect(() => {
    // Sets total with already present products in the card
    // This useEffect is called only at the first render
    prices.forEach((price) => {
      setTotal((total) => total + price);
    });
  }, []);

  useEffect(() => {
    setTotal((total) => total + prices[prices.length - 1]);
     // Called when prices values changes, like if you're adding a product to your card
     // It keeps your total updated
  }, [prices]);

  const addPrice = () => {
    // Simulate a new product in your card
    setPrices((prices) => [...prices, Math.floor(Math.random() * 10)]);
  };

  return (
    <div className="App">
      <p>total: {total}</p>
      <button onClick={() => addPrice()}>add price</button>
    </div>
  );

I hope I'm clear in my answer lol

Upvotes: 4

danihazler
danihazler

Reputation: 409

  const [finalTotal, setFinalTotal] = useState(0);

  let total = 0;
  for (let i = 0; i < prices.length; i++) {
    total += prices[i];
  }

  useEffect(() => {
    setFinalTotal(total);
  }, [total, setFinalTotal]);

https://codesandbox.io/s/stackoverflowhelp-i70fd?file=/src/App.js

Upvotes: 0

Related Questions