1

I've been working on a simple calculator app and I want commas to be displayed on the output. How do I go about it.

const [result, setResult] = useState("");

  const handleClick = (e) => {
    setResult(result.concat(e.target.name));
  };


  const calculate = () => {
    try {
      setResult(eval(result).toString());
    } catch (err) {
      setResult("Error");
    }
  };

I tried console logging the result with the .toLocaleString('en-US') method but it still doesn't work.

console.log(result.toLocaleString('en-US'))
Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Sire
  • 11
  • 1
  • too little code to know what it does – Vulwsztyn Sep 27 '22 at 17:04
  • Avoid using `eval` – Mr. Polywhirl Sep 27 '22 at 17:07
  • Don't use `eval` unless you really know what you're doing. The fact that you're calling `toLocaleString('en-US')` on a string value demonstrates you're not quite there. Use `parseInt` or `parseFloat` to get the numeric value, if that's what you're after. I get the feeling that you want to use numbers for all of these functions... – Heretic Monkey Sep 27 '22 at 17:08
  • @gog .toLocaleString() works but when i run the function(click the equal button) again it returns the last 3 digits of the value – Sire Sep 27 '22 at 19:43

1 Answers1

0

You should create a number display function like so:

const formatNumber = useCallback((n) => {
  const result = (+n).toLocaleString('en-US', { maximumFractionDigits: 8 });
  return showDecimal && result.indexOf('.') === -1 ? result + '.' : result;
}, [showDecimal]);

The tricky part is whether to show the decimal after formatting the number.

Full example

const { useCallback, useState } = React;

const CalculatorApp = () => {
  const [buffer, setBuffer] = useState(0);
  const [display, setDisplay] = useState('');
  const [mode, setMode] = useState(null);
  const [showDecimal, setShowDecimal] = useState(false);

  const formatNumber = useCallback((n) => {
    const result = (+n).toLocaleString('en-US', { maximumFractionDigits: 8 });
    return showDecimal && result.indexOf('.') === -1 ? result + '.' : result;
  }, [showDecimal]);

  const handleInput = useCallback(({ target: { value } }) => {
    setDisplay((curr) => {
      switch (value) {
        case '.':
          if (!showDecimal) {
            setShowDecimal(true);
            return (curr || 0) + value;
          }
          break;
        default:
          return curr + value;
      }
      return curr;
    });
  }, [showDecimal]);
  
  const handleOp = useCallback(({ target: { value } }) => {
    switch (value) {
      case '+':
      case '-':
      case '/':
      case '*':
       if (buffer && mode) {
          setBuffer((currBuffer) => {
            switch (mode) {
              case '+': return currBuffer + +display;
              case '-': return currBuffer - +display;
              case '/': return currBuffer / +display;
              case '*': return currBuffer * +display;
            }
            return currBuffer;
          });          
        } else {
          setBuffer(+display);
        }
        setMode(value);
        setDisplay('');
        setShowDecimal(false);
        break;
      case '=':
        setDisplay((currDisplay) => {
          switch (mode) {
            case '+': return buffer + +currDisplay;
            case '-': return buffer - +currDisplay;
            case '/': return buffer / +currDisplay;
            case '*': return buffer * +currDisplay;
          }
          return currDisplay;
        })
        setBuffer(0);
        setMode(null);
        setShowDecimal(false);
    }
  }, [buffer, display, mode]);
  
  const handleCond = useCallback(({ target: { value } }) => {
    switch (value) {
      case 'C':
        setBuffer(0);
        setMode(null);
      case 'CE':
        setDisplay('');
        setShowDecimal(false);
        break;
    }
  }, []);
  
  const handleKeyDown = useCallback(({ key }) => {
    switch (key) {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '.':
        handleInput({ target: { value: key } });
        break;
      case '+':
      case '-':
      case '/':
      case '*':
      case '=':
      case 'Enter':
        handleOp({ target: { value: key === 'Enter' ? '=' : key } });
        break;
    }
  }, [buffer, display, mode]);
  
  return (
    <div className="calculator" onKeyDown={handleKeyDown}>
      <div className="display-wrapper">
        <div className={`buffer ${(buffer && mode ? 'buffer-visible' : '')}`}>
          {formatNumber(buffer)} {mode}
        </div>
        <input className="display" type="text"
          placeholder="0"
          value={formatNumber(display)}
          readOnly />
      </div>
      <div className="button-grid">
        <div></div>
        <div></div>
        <button onClick={handleCond} value="CE">CE</button>
        <button onClick={handleCond} value="C">C</button>
        <button onClick={handleInput} value="7">7</button>
        <button onClick={handleInput} value="8">8</button>
        <button onClick={handleInput} value="9">9</button>
        <button onClick={handleOp} value="/">÷</button>
        <button onClick={handleInput} value="4">4</button>
        <button onClick={handleInput} value="5">5</button>
        <button onClick={handleInput} value="6">6</button>
        <button onClick={handleOp} value="*">×</button>
        <button onClick={handleInput} value="1">1</button>
        <button onClick={handleInput} value="2">2</button>
        <button onClick={handleInput} value="3">3</button>
        <button onClick={handleOp} value="-">-</button>
        <button onClick={handleInput} value="0">0</button>
        <button onClick={handleInput} value=".">.</button>
        <button onClick={handleOp} value="+">+</button>
        <button onClick={handleOp} value="=">=</button>
      </div>
    </div>
  );
};

ReactDOM
  .createRoot(document.getElementById("root"))
  .render(<CalculatorApp />);
* { margin: 0; padding: 0; }
*, *:before, *:after { box-sizing: border-box; }
html, body, #root { width: 100%; height: 100%; }

#root {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: #222;
}

.calculator {
  display: flex;
  flex-direction: column;
  width: 300px;
  gap: 0.25rem;
  background: #DDD;
  padding: 0.25rem;
  border: thin solid #FFF;
}
.display-wrapper {
  display: flex;
  flex-direction: column;
  border: thin solid grey;
  background: #FFF;
  padding: 0.125rem;
}
.display {
  font-family: monospace;
  text-align: right;
  font-size: 1.5rem;
  border: none;
  outline: none;
}
.buffer {
  font-family: monospace;
  text-align: right;
  visibility: hidden;
}
.buffer.buffer-visible {
  visibility: visible;
}
.button-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-row-gap: 0.125rem;
  grid-column-gap: 0.25rem;
}
.button-grid button {
  cursor: pointer;
  font-weight: bold;
  min-height: 1.25rem;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
Mr. Polywhirl
  • 42,981
  • 12
  • 84
  • 132