본문 바로가기

카테고리 없음

React로 계산기(calculator) 만들기

전에도 상세하게 올려보겠다던 계산기 코드를 이제야 올려본다
처음부터 로직을 생각하고 구현 해보았기에 의미 있고 실용성 있는 계산기가 되길 개인적으로 바란다

리액트로 계산기를 만드는 사람들은 많지 않을 것 이다

대부분이 자바스크립트를 기반으로 하고 있고 복잡한 구현이 아니기 때문에...

그렇지만 누군가가 나처럼 계산기를 리액트로 무조건 만들어야 하는 상황이 있다면 이 글을 읽고 꼭 도움이 되길 바란다

리액트 계산기 확인하기!!(클릭)

바로 코드를 치기 전 생각을 해보자
계산기의 동작 원리가 뭘까?
숫자 입력 >> 연산해줄 연산자 입력 >> 숫자 입력 >> 등호(=) 입력 >> 결과 출력
내가 생각한 계산기의 동작원리를 그대로 코드를 구현하면 된다고 생각했다

 

1. React Project 생성

CRA를 통한 리액트 프로젝트를 생성한다

나는 yarn을 사용하여 프로젝트를 생성하였다

 

REACT CRA(create-react-app)

yarn 

yarn create react-app my-app // my-app은 내가 생성하고 싶은 프로젝트 폴더명 이름을 바꾸어도 상관없다

 

2. 프로젝트의 디렉터리 구조 확인

src폴더의 APP.js만 사용했다 컴포넌트를 나누는 작업은 굳이 필요 없어하지 않았다

 

본격적인 계산기 만들기

계산기

여기서는 CSS는 설명하지 않는다 글 마지막 전체 코드를 참고하길 바란다

 

State 구성

  const [firstCalcNumber, setFirstCalcNumber] = useState('');
  const [secondCalcNumber, setSecondCalcNumber] = useState('');
  const [operator, setOperator] = useState('');
  const [result, setResult] = useState('');

필요한 State는 4개이다

- 첫 번째 숫자 입력이 들어갈 State

- 두 번째 숫자 입력이 들어갈 State

- 연산자 입력이 들어갈 State

- 결과값 입력이 들어갈 State

 

버튼을 클릭했을 때 숫자 입력이 들어가는 State에 값을 넣어주기

<button
 className="number-btn"
 onClick={() => {
 onClickNumber("7");
 }}
>
 7
</button>

계산기 7번 숫자의 버튼으로 예를 들어보자면 버튼에 onClick()을 부여한 뒤 콜백 함수를 통해 함수 onClickNumber("7")을 호출한다

 

onClickNumber()

  const onClickNumber = (number) => {
    if (!operator) {
      setFirstCalcNumber([...firstCalcNumber, number].join(''));
    } else {
      setSecondCalcNumber([...secondCalcNumber, number].join(''));
    }
  };

onClickNumber() 함수 안에서는 number라는 매개변수를 가지고 있고 조건문 if를 통해 operator state에 값이 없다면

첫 번째 숫자에 들어갈 입력 State에 값을 넣어주고 아니라면 두 번째 숫자에 들어갈 입력 State에 값을 넣어주라고 하는 조건식을 작성하였다

 

계산기의 숫자 7 버튼의 예를 들어 7 버튼을 누르면 operator의 값의 유무를 비교하여 연산자의 값이 없을 때는 무조건 첫 번째 숫자 State에

값이 들어간다

 

처음 동작원리를 생각해보자면

숫자 입력 >> 연산자 입력 >> 숫자입력 >> 등호 입력 >> 결과값 출력 중 숫자 입력이다

 

연산자(operator)를 클릭 시 연산자 값 State에 넣어주기

const [operator, setOperator] = useState('');
<button
 className="number-btn-orange"
 onClick={() => {
 handleOperator();
 setOperator("+");
}}
>
 +
</button>

연산자의 입력을 통해 마찬가지로 + 버튼을 눌렀을 시 operator State에 값이 담긴다

 

두 번째 숫자 입력 State에 값을 넣어주기 또한 연산자의 값을 통해 조건식을 위에서 주었기에

연산자 입력 >> 연산자 값 유무 확인 >> 숫자 입력 >>  두번째 숫자 state에 값 입력이 된다

 

여기까지 전체 코드를 보도록 하자

  const [firstCalcNumber, setFirstCalcNumber] = useState('');
  const [secondCalcNumber, setSecondCalcNumber] = useState('');
  const [operator, setOperator] = useState('');

  const onClickNumber = (number) => {
    if (!operator) {
      setFirstCalcNumber([...firstCalcNumber, number].join(''));
    } else {
      setSecondCalcNumber([...secondCalcNumber, number].join(''));
    }
  };

 

<button
 className="number-btn"
 onClick={() => {
 onClickNumber("3");
}}
>
 3
</button>

<button
 className="number-btn-orange"
 onClick={() => {
 handleOperator();
 setOperator("+");
}}
>
 +
</button>

 

등호 기호를 눌렀을 때 계산식 출력하기

<button
 className="number-btn orange-color"
 onClick={() => {
 handleOperator();
 checkOperator();
}}
>
 =
</button>

handleOperator()

const handleOperator = () => {
    let firstNumber = new Decimal(firstCalcNumber);
    if (operator === "+") {
      setResult(firstNumber.plus(secondCalcNumber)); // + 연산
    } else if (operator === "-") {
      setResult(firstNumber.minus(secondCalcNumber)); // - 연산
    } else if (operator === "X") {
      setResult(firstNumber.times(secondCalcNumber)); // * 연산
    } else if (operator === "/") {
      setResult(firstNumber.div(secondCalcNumber)); // 나누기 / 연산
    }
    setOperator(""); // 등호없이 연산하기 위한 state관리로 지금은 신경쓰지 말자
    setSecondCalcNumber(""); // 등호없이 연산하기 위한 state관리로 지금은 신경쓰지 말자
  };

operator State에 담긴 값이 사칙연산( + , - , * , / )에 따라 첫 번째 숫자와 두 번째 숫자를 연산자를 통해 계산하게 되는 계산식이다

여기서 Decimal이 뭔가 생각했을 텐데 컴퓨터는 정확한 정수가 아니라 실수를 계산하거나 활용할 때 부동소수점이 발생하여 정확한 계산이 이루어지지 않는다

 

정밀도 손실(부동소수점)

let a = 0.1;
let b = 0.2;

let c = a + b;

// 0.3이 아니다 false 정확히 계산이 되지 않는다

이는 컴퓨터 비트 수의 문제로 컴퓨터는 0 1 두 개의 숫자밖에 모르기 때문에 이를 변환하는 과정에서 이러한 문제가 발생하는 것이다

가장 좋은 방법은 실수를 사용하지 않는 것 그 자체이지만 (정수만 되도록 사용하라는 말이다) 이 같은 부동소수점 문제를 해결하고자

Decimal.API라는 것을 사용할 수 있다 부동소수점을 변환해주어 위와 같은 현상을 방지할 수 있다 plus minus times div는 사칙연산 Decimal의 문법이다

 

정밀도 손실과 관련하여 좋은 영상

https://www.youtube.com/watch?v=-GsrYvZoAdA

 

이렇게 계산된 값을 뷰(view)로 보여주기

<div className="view-number">
 <input
  className="view-number-title"
  readOnly="this.blur()"
  type="text"
  value={secondCalcNumber ? secondCalcNumber : firstCalcNumber}
 />
</div>

input의 value에 조건부 렌더링을 하여 view를 숫자의 state입력 때마다 바꾸어 변경하도록 구성

 

이 정도만 하여도 기본적인 정수를 가지고 사칙연산을 하는 데는 전혀 문제가 없다

이후는 소수점을 찍어서 계산할 수 있는 기능, 키보드를 이용하여 계산할 수 있는 기능, 계산할 수 없는 식을 예외처리하는 코드 등

계산기 하나로도 많은 기능을 추가할 수 있다

 

전체 코드의 깃허브를 올린다 누군가가 꼭 도움이 되길 바라면서...

https://github.com/jihoon8730/calculator

 

GitHub - jihoon8730/calculator

Contribute to jihoon8730/calculator development by creating an account on GitHub.

github.com

 

[참고]

유튜브 - 코딩애플