ogtm
ogtm

Reputation: 339

Calcul with useState in a map function javascript react

Hello guys I have an array like this :

[
 {
   "name": "test",
   "amount": 794.651786,
   "id": "60477897fd230655b337a1e6"
 },
 {
   "name": "test2",
   "amount": 10.80918,
   "id": "60477bfbfd230655b337a1e9"
 }
] 

And i wan't to make the total of every amount.

I tried by using the useState hook like this :

const [total, setTotal] = useState(Number);
array.map((item) => {

 setTotal(total + item.amount);

});

but it doesn't seems to work as expected.

Upvotes: 1

Views: 2108

Answers (4)

Adam Jenkins
Adam Jenkins

Reputation: 55663

My comment wasn't addressed but I'm going to add an answer which addresses my concern - total shouldn't be state at all.

total most likely isn't state - it's computed state - i.e. it's derived from other state and/or props.

If that's the case (99% that it is) it's not correct to set total as state, that just makes for more code and more complicated debugging:

Examples:

When the source of data is a prop:

const Cart = ({someItemsInMyCart}) => {
   const total = useMemo(() => someItemsInMyCart.reduce((acc,item) => acc+item.amount,0),[someItemsInMyCart]);

   return (/* some JSX */);
}

When the source of data is state:

const Cart = () => {
   const [items,setItems] = useState([]);
   const total = useMemo(() => items.reduce((acc,item) => acc+item.amount,0),[items]);

   return (/* some JSX */);
}

You can write those two examples above and completely leave out the useMemo, which is just a perf optimization, because reducing an array in that manner is pretty darn fast unless you're dealing with 1000s of items.

Upvotes: 2

Fabio Lopez
Fabio Lopez

Reputation: 527

You would want to update the state with the minimum calls needed. so first, I would do it like this:

let _total = 0;
array.forEach((item) => {
   _total += item.amount;
});
setTotal(_total);

That said, You would want to only execute this if array has changed. Assuming array is a prop, this can be done easily with useEffect hook:

useEffect(()=>{
    let _total = 0;
    array.forEach((item) => {
        _total += item.amount;
    });
setTotal(_total);
},[array]);

Hope this helps you get a full picture of what the best practice would be. Also you can check out the rules of hooks to get a better understanding on where is best to call setState

Upvotes: 3

jperl
jperl

Reputation: 5112

You could use the reduce method, see docs.

setTotal(array.reduce((sum, item) => sum + item.amount, 0))

I invite you to read this JavaScript: Difference between .forEach() and .map() as well. You should never use .map like this. For this use case, use .forEach instead.

Upvotes: 5

Surya
Surya

Reputation: 546

Try this way

const [total, setTotal] = useState(0);

array.map((item) => {
 setTotal(prevCount => prevCount + item.amount);    
});

Upvotes: 0

Related Questions