본문 바로가기

모바일 개발/React Native-이론

계산기 클론코딩 - 예외처리

<개요>

프로그램을 만들 때 수많은 예외처리가 필요하다. 

계산기에도 수많은 예외처리가 필요하지만 일단 몇 개만 해보자

 

문제1: 두 번째 값을 한 자리 수 밖에 클릭할 수 없는 이유 

문제가 발생하는 이유:

 const onPressNum = (num) => {
    if(currentOperator) {
      setResult(input);
      setInput(num);
    }
    else{
      const newInt = Number(`${input}${num}`)
      setInput(newInt)
    }
  };

첫번째 숫자 누르기 -> = 아닌 연산자 누르기 -> 두 번째 숫자 누르기 순으로 진행된다. 

위의 로직을 보면 현재 연산자가 골라져 있으면,  붙여쓰지 말고,  바로 바로 result로 값을 넘기게 되어있다. 그래서 두 번째 숫자에서는 한 자리수 초과해서 쓸 수 없는 것이다. 

 

해결방안:

이를 막으려면, 

=이 아닌 연산자를 누르고 난 뒤 맨 처음 숫자 패드를 누를 때, 이미 써 있던 첫 번째 숫자는 result로 빼고, input 창이 초기화 되게 한다. 

두 번째 패드 누르기 부터는 이어붙일 수 있게 한다 .

 

이를 위해서 boolean useState 구문이 필요하다. 

const[isClickedOperator, setIsClickedOperator] = useState(false);

초기 상태는 false 이다. 

그리고 연산자를 누르는 순간에 연산자를 눌렀냐를 묻는 isClickedOperator를 true로 바꿔준다. 

그리고 숫자 패드를 눌렀을 때 동작하는 함수를 손 보겠다. 

  const onPressNum = (num) => {
    if(currentOperator && isClickedOperator) {
      setResult(input);
      setInput(num);
      setIsClickedOperator(false);
    }
    else{
      const newInt = Number(`${input}${num}`)
      setInput(newInt)
    }
  };

만약에 직전에 연산자를 눌렀으면 if 구문이 실행 될 것이다. 그리고 if 구문 맨 마지막에 보면 setIsClickedOperator를 false로 바꾸었다. 

다음 번에 사용자가 다시 숫자 패드를 누른다면 이제 IsClickedOperator가 false 이니 else 구문이 실행될 것이다. 

문제 2.

하나의 계산을 끝낸 뒤 =을 다시 누르면, 직전 연산자와 두번째 입력 숫자로 계속 연산이 이루어져야 하는데, 자꾸 입력창에 있는 내용으로 연산이 이루어짐 

(예시: 12+ 3 = 15를 했음. 이 뒤에 =을 누르면 15+3 = 18, 다시 = 누르면 18+ 3 = 21... 이런 식으로 가야함.)

(현재 상태: 12+3 = 15를 했음. 이 뒤에 =을 누르면 입력창의 15가 또 더해짐. 15+ 15 = 30, 다시 = 누르면 30 + 30 = 60...)

 

문제가 생긴 이유: 

현재 계산 함수를 보면 =을 누른다면, 계속 result와 input을 더 함. 

그러니까 result와 input은 같은 값이기에 = 누르면 계속 *2가 될 뿐이다.

(계산 결과를 상태창에 띄우기 때문에 상태창에 표시되는 input도 계속 최신화 된다. )

해결 방안:

현재 보면 두번째 입력을 저장하는 공간이 없다. 

두 번째 입력을 tempInput에 저장하고, =을 눌렀을 시, 직전에 =을 누른 전력이 있다면 result + tempInput  , 직전에 = 누른 이력이 없다면 result + input 형태로 가면 될 것이다.

 

직전에 눌렀는지 보여주는 useState()

const[isClickedEqual, setIsClickedEqual] = useState(false);
  const onPressOperator = (operator) => {
    
    

    if(operator !== "=") {
      setCurrentOperator(operator)
      setIsClickedOperator(true)
      setIsClickedEqual(false)
    }
    else{
      let finalResult = result;
      const finalInput = isClickedEqual ? tempInput : input;
     
      switch (CurrentOperator) {
        case "*":
          finalResult *= finalInput;
          break;
        case "/":
          finalResult /= finalInput;
          break;
        case "+":
          finalResult += finalInput;
          break;
        case "-":
          finalResult -= finalInput;
        default:
          break;
      }
      setInput(finalResult);
      setResult(finalResult); 
      setTempInput(finalInput);
      setIsClickedEqual(true);
    }
  };

=을 눌렀다면 setIsClickedEqual(true)를 통해 IsEqual이  true로 toggle 된다.

 

문제3: =을 누르면 제일 최근에 누른 연산자에서의 border 굵기 없애주기 

 

= 눌렀을 시 currentOperator가 null이 되도록 setCurrentOperator(null)를 연산 함수에 추가

 

버튼의 속성을 보면 Border 굵기 toggle을 위해 쓰이는 isSelected가 currentOperator가 들어감을 알 수 있다. 

근데 currentOperator = null 이 되면 어느 연산이건 isSelected가 false가 되어 테두리 굵기가 빠진다. 

 

문제점: 

우리가 연산을 할 때  CurrentOperator를 사용하여, 연산했는데, 이 녀석이 null이 되면 =을 눌러도 다시 재 연산이 불가능 해진다. 

이를 방지하기 위해서 CurrentOperatior의 값을 저장해둘 임시 저장소 tempOperator를 만든다. 

그리고 아까 2번과 같이 직전에 =을 눌렀다면 Current Operator 대신에 tempOperator가 연산에 쓰이도록 만든다. 

문제4: ALL CLEAR와 CLEAR 구분 

모든 내용 전부 지우고 싶을 때 AC 

방금 내가 입력한 input만 지우고 싶을 때 C 

 

C 버튼을 한번 더 누르면 AC 버튼이 되도록 만들자. 

C를 누르면 input === 0 이 되므로 

input이 0인가? 해서 true이면 AC 버튼이 되고 아니면 C 버튼이 되도록 로직을 짜면 된다.

  /* const hasInput = input? true : false; */
  
  /* 숫자나 String 값을 boolean으로 바꾸려면 이중부정 해주면 된다. */
  const hasInput = !!input;

text 부분
리셋 부분

 

2. 4개의 문제 예외처리 스스로 해보기

 

다음 날 했는데도 안 보고 잘함. 

리뷰할 때 그림을 그리니까 똑같은 상황이 닥쳐도 그림이 그려져서 할 수 있는 것 같음.