본문 바로가기

CodeSoom- React 13기

[코드숨] 리액트 13기 -1강/과제 2 - 간단한 사칙 연산 계산기 구현 과제 풀이

오류

main.js:287 Uncaught RangeError: Maximum call stack size exceeded

=>계속 실행됨

 

▼ 오류원인

 

 <button type="button" onClick={handleClickOperator('+')}>
  +
 </button>

 

 해결: 함수를 그냥 넣어주게 아니라 () 해서 작성했기 때문에 아래와 같이 작성해야 함.

<button type="button" onClick={() => handleClickOperator('+')}>
 +
</button>

 


 

▼ 아샬코드

 

/* @jsx createElement */

function createElement(tagName, props, ...children) {
  const element = document.createElement(tagName);

  Object.entries(props || {}).forEach(([key, value]) => {
    element[key.toLowerCase()] = value;
  });

  children.flat().forEach((child) => {
    if (child instanceof Node) {
      element.appendChild(child);
      return;
    }
    element.appendChild(document.createTextNode(child));
  });

  return element;
}

//
// ㄱ.const defaultFunction = (x, y) => x || y;

/* ㄴ.
function plus(x, y) {
  return x + y;
} */

const operatorFunctions = {
  /*  '': (x, y) => x || y, // 처음엔 x가 없으니까 y만
  '=': (x, y) => x || y, // 처음엔 x가 없으니까 y만 */

  /*  ㄴ. 위의 함수를 끌어쓰고 싶으면
  '+': plus, // 이렇게도 표현가능한데 여기선 간략한 거 씀 */
  '+': (x, y) => x + y,
  '-': (x, y) => x - y,
  '*': (x, y) => x * y,
  '/': (x, y) => x / y,
};

function or(x, y) {
  return x === null ? y : x;
}

// ㄱ다르게 표현
function defaultFunction(x, y) {
  return or(y, x);
  // return y, x;
}

function calculate(operator, accumulator, number) {
  return (operatorFunctions[operator] || defaultFunction)(accumulator, number);
}//  ||defaultFunction :  함수값을 못얻으면 이거 출력 ex:만약 ''버튼이 없거나 =가 없는 경우를 설정해서 위처럼 없어도 작동되게 할 수 있다}}

//
const initialState = {
  accumulator: 0, // 계속해서 누적돼서 계산되는값,result도 가능 (12누르고 + 9 일경우 129가 안되게 +누른순간 12를 저장해야함=>12가 누적된다)
  number: null,
  operator: '',
};

function render({ accumulator, number, operator }) {
  function handleClickReset() {
    render(initialState);
  }

  function handleClickNumber(value) {
    render({
      accumulator,
      number: (number || 0) * 10 + value,
      operator, // operator:operator, 축약
    });
  }

  function handleClickOperator(value) {
    render({
      accumulator: calculate(operator, accumulator, number), // 기존에 입력했던 숫자값
      number: null,
      operator: value,
    });
  }

  const element = (
    <div>
      <p>CoseSoom assignment 2</p>
      <p>{or(number, accumulator)}</p>
      {/* 없을경우는 다른거 보여줌 */}
      <p>
        {[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map((i) => (
          <button type="button" onClick={() => handleClickNumber(i)}>
            {i}
          </button>
        ))}
      </p>
      <p>
        {['+', '-', '*', '/', '='].map((i) => (
          <button type="button" onClick={() => handleClickOperator(i)}>
            {i}
          </button>
        ))}
        <button type="button" onClick={handleClickReset}>
          Reset
        </button>
      </p>
    </div>
  );

  document.getElementById('app').textContent = '';
  document.getElementById('app').appendChild(element);
}

render(initialState);

 

 

▼ 내코드 중간 (끝인줄 알았으나 오류발견)

 
/* eslint-disable react/react-in-jsx-scope, react/jsx-filename-extension, no-unused-vars */

/* @jsx createElement */

function createElement(tagName, props, ...children) {
  const element = document.createElement(tagName);

  Object.entries(props || {}).forEach(([key, value]) => {
    element[key.toLowerCase()] = value;
  });

  children.flat().forEach((child) => {
    if (child instanceof Node) {
      element.appendChild(child);
      return;
    }
    element.appendChild(document.createTextNode(child));
  });

  return element;
}

const initialState = {
  number: 0,
  resultNumber: 0,
  operator: '',
};

const operators = {
  '': (x, y) => y,
  '+': (x, y) => x + y,
  '-': (x, y) => x - y,
  '*': (x, y) => x * y,
  '/': (x, y) => x / y,
  '=': (x, y) => y,
};

function calculate(number, resultNumber, operator) {
  return operators[operator](resultNumber, number);
}

function render({ number, resultNumber, operator }) {
  function clickNumber(value) {
    render({
      number: number * 10 + value,
      resultNumber,
      operator,
    });
  }

  function clickOperator(value) {
    render({
      number: 0,
      resultNumber: calculate(number, resultNumber, operator),
      operator: value,
    });
  }

  const element = (
    <div>
      <h3>CoseSoom assignment 2</h3>
      <p>간단 계산기</p>
      <p>{number || resultNumber}</p>
      <p>
        {[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map((i) => (
          <button type="button" onClick={() => clickNumber(i)}>
            {i}
          </button>
        ))}
      </p>
      <p>
        {Object.keys(operators).filter((data) => data !== '').map((i) => (
          <button type="button" onClick={() => clickOperator(i)}>
            {i}
          </button>
        ))}

      </p>
    </div>
  );

  document.getElementById('app').textContent = '';
  document.getElementById('app').appendChild(element);
}

render(initialState);
 

오류

1.강의를 들은후 다시 살펴보니, 위 코드에서 오류발견(5+5=10, 이상태에서 -를 다시 누르고5하면 계산된 값이

나와야하는데 내꺼는 다시 0으로 리셋되게 만들어버림)

2. 9+0을 누르면 0이 위에 누른 숫자출력에 보여야하는데 안보임 =>number값을 null이었을때를 이용하여 수정

 

(강의 참고)

정정

  1. defaultFunction에서 xy를 다루는 순서가 반대로 되어 있어서 순서를 바꿔야 합니다.
  2. 0이 입력이 안되는 문제가 있습니다.

JavaScript에서는 null을 이용해서 정말로 빈 값을 표현할 수 있습니다. or라는 함수를 만들어서 0은 그대로 사용하고 null일 때만 다른 값을 취하게 하여 문제를 해결할 수 있습니다.

▼ 강의에 써있는 말 이해돕기(number를 null값으로 수정하여 0을 눌렀을때도 출려되게 만들어줌)

▼이를 통해 수정한 내 최종 코드

/* eslint-disable react/react-in-jsx-scope, react/jsx-filename-extension, no-unused-vars */

/* @jsx createElement */

function createElement(tagName, props, ...children) {
  const element = document.createElement(tagName);

  Object.entries(props || {}).forEach(([key, value]) => {
    element[key.toLowerCase()] = value;
  });

  children.flat().forEach((child) => {
    if (child instanceof Node) {
      element.appendChild(child);
      return;
    }
    element.appendChild(document.createTextNode(child));
  });

  return element;
}

const initialState = {
  number: null,
  resultNumber: 0,
  operator: '',
};

const operators = {
  '+': (x, y) => x + y,
  '-': (x, y) => x - y,
  '*': (x, y) => x * y,
  '/': (x, y) => x / y,
  '=': (x, y) => x || y,
};

function or(x, y) {
  return x === null ? y : x;
}

function defaultFunction(x, y) {
  return or(y, x);
}

function calculate(number, resultNumber, operator) {
  return (operators[operator] || defaultFunction)(resultNumber, number);
}

function render({ number, resultNumber, operator }) {
  function clickNumber(value) {
    render({
      number: (number || 0) * 10 + value,
      resultNumber,
      operator,
    });
  }

  function clickOperator(value) {
    render({
      number: null,
      resultNumber: calculate(number, resultNumber, operator),
      operator: value,
    });
  }

  function handleClickReset() {
    render(initialState);
  }

  const element = (
    <div>
      <h3>CoseSoom assignment 2</h3>
      <p>간단 계산기</p>
      <p>{or(number, resultNumber)}</p>
      <p>
        {[1, 2, 3, 4, 5, 6, 7, 8, 9, 0].map((i) => (
          <button type="button" onClick={() => clickNumber(i)}>
            {i}
          </button>
        ))}
      </p>
      <p>
        {Object.keys(operators).filter((data) => data !== '').map((i) => (
          <button type="button" onClick={() => clickOperator(i)}>
            {i}
          </button>
        ))}
        <button type="button" onClick={handleClickReset}>
          Reset
        </button>
      </p>
    </div>
  );

  document.getElementById('app').textContent = '';
  document.getElementById('app').appendChild(element);
}

render(initialState);