React calculator too many renders

Viewed 63

I am trying to build a calculator. The issue is, I am trying to do something like 1 + 3 for example, and although I can display the 1 and 3, I can't put the '+' in between them (operation), I tried adding an onClick and it gives to many re-renders.

I tried onClick={sum}, and onClick={() => sum()} and even onClick={(e) => sum(e)} to then use e.preventDefault() on my sum function but it keeps giving the same error, it does not do it.

I know that if it was an input field an onChange would easily do it, but with q button that onChange is not an option, so I am stuck.

import React, { useState, useEffect } from "react";

    const Calculator = () => {
      const [firstValue, setFirstValue] = useState('')
      const [secondValue, setSecondValue] = useState('')
      const [operation, setOperation] = useState('')
      const [value, setValue] = useState('')
    
      function sum() {
        // e.preventDefault()
        setOperation('+')
      }
    
      function clear() {
        setFirstValue('')
        setSecondValue('')
        setOperation('')
      }
    
      // useEffect(() => {
      // }, [operation, firstValue, secondValue, value])
    
      if (operation === "+") {
        setValue(parseInt(firstValue) + parseInt(secondValue))
      }
      if (operation === "-") {
        setValue(parseInt(firstValue) - parseInt(secondValue))
      }
      if (operation === "x") {
        setValue(parseInt(firstValue) * parseInt(secondValue))
      }
      if (operation === "/") {
        setValue(parseInt(firstValue) / parseInt(secondValue))
      }
    
      return (
        <div className="calculator">
          <div data-testid="name">Calculator</div>
    
          <div data-testid="display" className="display">{firstValue} {operation} {secondValue}</div>
    
          <div className="number-inputs">
            <input onChange={(e) => setFirstValue(e.target.value)} data-testid="num1" id="num1" type="number"></input>
    
            <div data-testid="selected-operation">{operation}</div>
            <input onChange={(e) => setSecondValue(e.target.value)} data-testid="num2" id="num2" type="number"></input>
          </div>
    
          <div className="operation-selectors">
            <button onClick={() => sum()} data-testid="add">+</button>
            <button data-testid="sub">-</button>
            <button data-testid="mul">x</button>
            <button data-testid="div">/</button>
          </div>
    
          <div className="options">
            <button onClick={() => clear()} data-testid="clear" className="clear">
              Clear
            </button>
            <button data-testid="calc">Calculate</button>
          </div>
    
          <div data-testid="error" id="error" className="error"></div>
        </div>
      );
    };
    
    export default Calculator;

I read somewhere to do a calculator mounts which I think mounts is useEffect but the class based way? So if I am assuming the calculator mounts wrong, I would love to be corrected on that as well, I only know some react using hooks so I am clueless when it comes to class based, but I think that's what it means by calculator mounts.

I am also confused because the clear functions works just fine, although it is just setting the state to empty strings, it still "updates" the state, so I thought it would work the same for function sum but it did not work.

1 Answers

Move the if conditions inside useEffect.

useEffect(() => {
    if (operation === "+") {
      setValue(parseInt(firstValue) + parseInt(secondValue));
    }
    if (operation === "-") {
      setValue(parseInt(firstValue) - parseInt(secondValue));
    }
    if (operation === "x") {
      setValue(parseInt(firstValue) * parseInt(secondValue));
    }
    if (operation === "/") {
      setValue(parseInt(firstValue) / parseInt(secondValue));
    }
  }, [operation, firstValue, secondValue]);
Related