1

I have multiple inputs where user fill these inputs with numbers. I need a way to sum up the values of these inputs when user types in any input.

My Code

const [values,set_values] = useState({
    sales:'',
    bank_deposit:'',
    supply:'',
    expenses:''
})

const values_handler = (e) => {
    let name= e.target.name;
    let value= e.target.value;
    values[name]=value;
    set_values(values)

    // Calling the method to sum the value
    calc_total(value) 
}

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

const calc_total = (value) => {
    total +=value;
    set_total(total)
}

<input type='number' onChange={value_handler} name='sales' />
<input type='number' onChange={value_handler} name='bank_deposit' />
<input type='number' onChange={value_handler} name='supply' />
<input type='number' onChange={value_handler} name='expenses' />

Problem

The problem with this is that the values are summed up each time the value of an input got a chane, so that if user enters 15, it sums 1 then 5 since the mehtod is executed when a change occurred on the input's value.

5
  • values[name]=value; changes state; you're not supposed to do that. Commented Apr 21, 2020 at 17:53
  • @ChrisG This to assign the value in its element in values array Commented Apr 21, 2020 at 18:00
  • I know what you're trying to do, I'm telling you you're not allowed to do that in React. You need to create a copy of values, change the copy's number, then call set_values() passing the copy. Commented Apr 21, 2020 at 18:01
  • @ChrisG it would be great if you answer it, so we can benefit from the question, as i searched out how to do this but didn't got a clear answer, so i made this simple question to let everyone understands it. i updated the question with the problem Commented Apr 21, 2020 at 18:06
  • 1
    Right, you're doing this to help others. The problem here is that your code doesn't even attempt to sum up the values from your actual state. Do this: codesandbox.io/s/autumn-tdd-mm4xf?file=/src/App.js Commented Apr 21, 2020 at 18:10

3 Answers 3

2
  • you must not mutate the state values.
  • state updates are async.
  • you need not use the value of each onChange instead use the state values to update total value

Assuming you want to sum sales, bank_deposit, supply and expeses values, you can get them from states do it like below

const [values,set_values] = useState({
    sales:'',
    bank_deposit:'',
    supply:'',
    expenses:''
})

const values_handler = (e) => {
    let name= e.target.name;
    let value= e.target.value;
    const newValues = {
        ...values,
        [name]: value
    } 
    set_values(newValues)

    // Calling the method to sum the value
    calc_total(newValues) 
}

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

const calc_total = (newValues) => {
    const { sales, bank_deposit, expenses, supply} = newValues;
    const newTotal = parseInt(sales) + parseInt(bank_deposit) + parseInt(expenses) + parseInt(supply)
    setTotal(newTotal)

} 

<input type='number' onChange={value_handler} name='sales' />
<input type='number' onChange={value_handler} name='bank_deposit' />
<input type='number' onChange={value_handler} name='supply' />
<input type='number' onChange={value_handler} name='expenses' />
Sign up to request clarification or add additional context in comments.

3 Comments

calc_total is adding strings
Updated my answer, I just left it previously assuming that to not be that important a detail ;-)
OP wants working code on a silver platter, so why not go the extra mile for them ;)
0

try this:

const [values,set_values] = useState({
    sales:'',
    bank_deposit:'',
    supply:'',
    expenses:''
})

const values_handler = (e) => {
    let name= e.target.name;
    let value= e.target.value;
    set_values({...values , [name]: value})

// Calling the method to sum the value
calc_total(values) 
}

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

const calc_total = (values) => {
    aux = 0
    for (var key in values){
        aux += values[key]
    }
    set_total(aux)
}

<input type='number' onChange={value_handler} name='sales' />
<input type='number' onChange={value_handler} name='bank_deposit' />
<input type='number' onChange={value_handler} name='supply' />
<input type='number' onChange={value_handler} name='expenses' />

Remarks: Using Chris G. recommendations in the comments

1 Comment

values isn't an array, for one.
0
const Solution = () => {
  const [input_values, set_inputvalues] = useState({
    sales: 0,
    bank_deposit: 0,
    supply: 0,
    expenses: 0
  });

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

  useEffect(() => {
    const arrValues = Object.values(input_values);
    const inputTotals = arrValues.reduce((accum, curr) => (accum += curr), 0);
    set_total(inputTotals);
  }, [input_values]);

  const changeValues = ({ name, value }) => {
    set_inputvalues({ ...input_values, [name]: parseInt(value) });
  };

  return (
    <div>
      <h1>{total}</h1>
      <input
        type="number"
        onChange={({ target }) => changeValues(target)}
        name="sales"
      />
      <input
        type="number"
        onChange={({ target }) => changeValues(target)}
        name="bank_deposit"
      />
      <input
        type="number"
        onChange={({ target }) => changeValues(target)}
        name="supply"
      />
      <input
        type="number"
        onChange={({ target }) => changeValues(target)}
        name="expenses"
      />
    </div>
  );
};

To some up some key gotchas which other's have mentioned:

  • Don't alter state directly, use a set_xxx to update state.
  • You set type="number" so default state has to be numeric, i.e. sales: 0
  • Remember to parse values to int if numeric.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.