diff --git a/.gitignore b/.gitignore
index 4d29575..f491785 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,8 +2,6 @@
# dependencies
/node_modules
-/.pnp
-.pnp.js
# testing
/coverage
diff --git a/REQUIREMENTS.md b/REQUIREMENTS.md
index e82e733..a41117e 100644
--- a/REQUIREMENTS.md
+++ b/REQUIREMENTS.md
@@ -1,5 +1,7 @@
## 요구 사항
+### Step 1
+
- [x] Class Component를 사용합니다.
- [x] 레벨1을 참고하여 REQUIREMENTS.md에 요구 사항 도출
- [x] 2개의 숫자에 대해 덧셈이 가능하다.
@@ -12,3 +14,9 @@
- [x] 출력값 있는 상황에 사용자의 페이지 이탈시 confirm을 활용해 사용자의 이탈 여부를 확인한다.
- [x] 항상 사용자의 이탈시 마지막 출력값을 Local Storage에 저장한다.
- [x] 연산의 결과값이 Infinity일 경우 오류라는 문자열을 보여준다. (아이폰 참고)
+
+### Step 2
+
+- [x] Step1의 Class Component를 Function Component로 마이그레이션 합니다.
+- [x] Step1에서의 피드백을 적용합니다.
+- [x] 전체 코드를 리팩토링 합니다.
diff --git a/public/index.html b/public/index.html
index aa069f2..a11b18b 100644
--- a/public/index.html
+++ b/public/index.html
@@ -1,5 +1,5 @@
-
+
@@ -7,37 +7,14 @@
-
-
- React App
+ 리액트 계산기
-
+
-
diff --git a/public/robots.txt b/public/robots.txt
index e9e57dc..eb05362 100644
--- a/public/robots.txt
+++ b/public/robots.txt
@@ -1,3 +1,2 @@
-# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
diff --git a/src/App.js b/src/App.js
deleted file mode 100644
index 52c91fb..0000000
--- a/src/App.js
+++ /dev/null
@@ -1,137 +0,0 @@
-import React, { Component } from "react";
-import DisplayResult from "./component/DisplayResult";
-import CalculatorButton from "./component/CalculatorButton";
-
-export default class App extends Component {
- state = {
- firstNumber: 0,
- operator: null,
- secondNumber: 0,
- isFirstNumber: true,
- result: 0,
- };
-
- componentDidMount() {
- const prevValue = localStorage.getItem("prevValue") || 0;
- this.setFirstNumber(Number(prevValue));
- this.setResult(Number(prevValue));
-
- window.addEventListener("beforeunload", function (e) {
- e.preventDefault();
- e.returnValue = "";
- });
- }
-
- initState = () => {
- this.setState({
- firstNumber: 0,
- operator: null,
- secondNumber: 0,
- isFirstNumber: true,
- result: 0,
- });
- };
-
- setFirstNumber = (number) => {
- this.setState(
- {
- firstNumber: Number(number),
- },
- localStorage.setItem("prevValue", number)
- );
- };
-
- setOperator = (operator) => {
- this.setState({ operator });
- };
-
- setSecondNumber = (number) => {
- this.setState(
- {
- secondNumber: Number(number),
- },
- localStorage.setItem("prevValue", number)
- );
- };
-
- setResult = (result) => {
- this.setState({ result });
- };
-
- setIsFirstNumber = (isFirstNumber) => {
- this.setState({ isFirstNumber });
- };
-
- calculate = () => {
- const res = (() => {
- switch (this.state.operator) {
- case "+":
- return this.add();
- case "-":
- return this.sub();
- case "X":
- return this.multiple();
- case "/":
- return this.divide();
- default:
- throw new Error("존재하지 않는 연산자입니다.");
- }
- })();
-
- this.setState({ result: res }, () => {
- this.initState();
-
- if (res === Infinity || isNaN(res)) {
- this.setFirstNumber(0);
- this.setResult("오류");
- localStorage.setItem("prevValue", "오류");
- return;
- }
-
- this.setFirstNumber(res);
- this.setResult(res);
- localStorage.setItem("prevValue", res);
- });
- };
-
- add() {
- return this.state.firstNumber + this.state.secondNumber;
- }
-
- sub() {
- return this.state.firstNumber - this.state.secondNumber;
- }
-
- divide() {
- return Math.floor(this.state.firstNumber / this.state.secondNumber);
- }
-
- multiple() {
- return this.state.firstNumber * this.state.secondNumber;
- }
-
- render() {
- return (
- <>
-
- >
- );
- }
-}
diff --git a/src/Calculator.js b/src/Calculator.js
new file mode 100644
index 0000000..e55b5c7
--- /dev/null
+++ b/src/Calculator.js
@@ -0,0 +1,97 @@
+import React, { useEffect, useState, useCallback } from "react";
+import DisplayResult from "./component/DisplayResult";
+import NumberButton from "./component/buttons/NumberButton";
+import ModifierButton from "./component/buttons/ModifierButton";
+import OperatorButton from "./component/buttons/OperatorButton";
+import calculate from "./utils/calculate";
+
+import "./css/calculator.css";
+
+export default function App() {
+ const [firstNumber, setFirstNumber] = useState(0);
+ const [operator, setOperator] = useState(null);
+ const [secondNumber, setSecondNumber] = useState(0);
+ const [isFirstNumber, setIsFirstNumber] = useState(true);
+ const [result, setResult] = useState(0);
+
+ useEffect(() => {
+ const prevValue = localStorage.getItem("prevValue") || result;
+ setFirstNumber(Number(prevValue));
+ setResult(Number(prevValue));
+
+ window.addEventListener("beforeunload", function (e) {
+ e.preventDefault();
+ e.returnValue = "";
+ });
+ }, []);
+
+ const onClickNumber = (e) => {
+ const inputNumber = e.target.textContent;
+ const resultNumber = result === 0 ? inputNumber : result + inputNumber;
+ setResult(resultNumber);
+
+ if (isFirstNumber) {
+ setFirstNumber(firstNumber * 10 + Number(inputNumber));
+ return;
+ }
+
+ setSecondNumber(secondNumber * 10 + Number(inputNumber));
+ };
+
+ const onClickOperator = (e) => {
+ if (firstNumber === "") return;
+
+ const inputOperator = e.target.textContent;
+ if (inputOperator === "=" && secondNumber === "") return;
+
+ if (inputOperator !== "=") {
+ setResult(result + inputOperator);
+ setOperator(inputOperator);
+ setIsFirstNumber(false);
+ return;
+ }
+
+ onCalculate();
+ };
+
+ const onClickModifier = useCallback(() => {
+ setFirstNumber(0);
+ setSecondNumber(0);
+ setOperator(null);
+ setIsFirstNumber(true);
+ setResult(0);
+ localStorage.setItem("prevValue", 0);
+ }, []);
+
+ const onCalculate = () => {
+ const res = calculate(firstNumber, secondNumber, operator);
+
+ if (res === Infinity || isNaN(res)) {
+ setFirstNumber(0);
+ setSecondNumber(0);
+ setResult("오류");
+ setOperator(null);
+ setIsFirstNumber(true);
+ localStorage.setItem("prevValue", "오류");
+ return;
+ }
+
+ setFirstNumber(res);
+ setSecondNumber(0);
+ setResult(res);
+ setOperator(null);
+ setIsFirstNumber(true);
+ localStorage.setItem("prevValue", res);
+ };
+
+ return (
+
+ );
+}
diff --git a/src/component/CalculatorButton.js b/src/component/CalculatorButton.js
deleted file mode 100644
index c1eb7c5..0000000
--- a/src/component/CalculatorButton.js
+++ /dev/null
@@ -1,69 +0,0 @@
-import React, { Component } from "react";
-
-export default class CalculatorButton extends Component {
- onClickNumber = (e) => {
- const inputNumber = e.target.textContent;
- if (this.props.result === 0) {
- this.props.setResult(inputNumber);
- } else {
- this.props.setResult(this.props.result + inputNumber);
- }
-
- if (this.props.isFirstNumber) {
- this.props.setFirstNumber(
- this.props.firstNumber * 10 + Number(inputNumber)
- );
- return;
- }
- this.props.setSecondNumber(this.props.secondNumber + inputNumber);
- };
-
- onClickOperator = (e) => {
- const inputOperator = e.target.textContent;
- if (this.props.firstNumber === "") return;
- if (inputOperator === "=" && this.props.secondNumber === "") return;
- this.props.setResult(this.props.result + inputOperator);
- if (inputOperator !== "=") {
- this.props.setFirstNumber(this.props.firstNumber);
- this.props.setOperator(inputOperator);
- this.props.setIsFirstNumber(false);
- return;
- }
-
- this.props.calculate();
- };
-
- onClickModifier = () => {
- this.props.initState();
- localStorage.setItem("prevValue", 0);
- };
-
- render() {
- return (
- <>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- >
- );
- }
-}
diff --git a/src/component/DisplayResult.js b/src/component/DisplayResult.js
index f58beba..a91d82a 100644
--- a/src/component/DisplayResult.js
+++ b/src/component/DisplayResult.js
@@ -1,7 +1,5 @@
-import React, { Component } from "react";
+import React from "react";
-export default class DisplayResult extends Component {
- render() {
- return {this.props.result.toString()}
;
- }
+export default function DisplayResult(props) {
+ return {props.result.toString()}
;
}
diff --git a/src/component/buttons/ModifierButton.js b/src/component/buttons/ModifierButton.js
new file mode 100644
index 0000000..a6177c1
--- /dev/null
+++ b/src/component/buttons/ModifierButton.js
@@ -0,0 +1,7 @@
+export default function ModifierButton(props) {
+ return (
+
+
+
+ );
+}
diff --git a/src/component/buttons/NumberButton.js b/src/component/buttons/NumberButton.js
new file mode 100644
index 0000000..52cea9a
--- /dev/null
+++ b/src/component/buttons/NumberButton.js
@@ -0,0 +1,13 @@
+import { numberOfButtons, MaxButtonNumber } from "../../constants/constants";
+
+export default function NumberButton(props) {
+ return (
+
+ {Array.from({ length: numberOfButtons }, (_, i) => (
+
+ ))}
+
+ );
+}
diff --git a/src/component/buttons/OperatorButton.js b/src/component/buttons/OperatorButton.js
new file mode 100644
index 0000000..1881fb5
--- /dev/null
+++ b/src/component/buttons/OperatorButton.js
@@ -0,0 +1,13 @@
+import { operations } from "../../constants/constants";
+
+export default function OperatorButton(props) {
+ return (
+
+ {Array.from(operations, (v, _) => (
+
+ ))}
+
+ );
+}
diff --git a/src/constants/constants.js b/src/constants/constants.js
new file mode 100644
index 0000000..ea813a6
--- /dev/null
+++ b/src/constants/constants.js
@@ -0,0 +1,4 @@
+export const numberOfButtons = 10;
+export const MaxButtonNumber = numberOfButtons - 1;
+export const operations = ["/", "X", "-", "+", "="];
+export const ErrorMessage = "존재하지 않는 연산자입니다.";
diff --git a/src/index.css b/src/css/calculator.css
similarity index 86%
rename from src/index.css
rename to src/css/calculator.css
index a8460c4..16df4d3 100644
--- a/src/index.css
+++ b/src/css/calculator.css
@@ -1,17 +1,3 @@
-html,
-body {
- margin: 0;
- padding: 0;
- font-family: sans-serif;
-}
-
-#app {
- height: 100vh;
- display: flex;
- justify-content: center;
- align-items: center;
-}
-
.calculator {
width: 300px;
display: grid;
diff --git a/src/css/index.css b/src/css/index.css
new file mode 100644
index 0000000..e41af14
--- /dev/null
+++ b/src/css/index.css
@@ -0,0 +1,13 @@
+html,
+body {
+ margin: 0;
+ padding: 0;
+ font-family: sans-serif;
+}
+
+#app {
+ height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
diff --git a/src/index.js b/src/index.js
index 31508db..0329bf7 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,11 +1,11 @@
import React from "react";
import ReactDOM from "react-dom/client";
-import "./index.css";
-import App from "./App";
+import "./css/index.css";
+import Calculator from "./Calculator";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
-
+
);
diff --git a/src/utils/calculate.js b/src/utils/calculate.js
new file mode 100644
index 0000000..a4feea4
--- /dev/null
+++ b/src/utils/calculate.js
@@ -0,0 +1,36 @@
+import { ErrorMessage } from "../constants/constants";
+
+const calculateValue = (firstNumber, secondNumber, operator) => {
+ return (() => {
+ switch (operator) {
+ case "+":
+ return add(firstNumber, secondNumber);
+ case "-":
+ return sub(firstNumber, secondNumber);
+ case "X":
+ return multiple(firstNumber, secondNumber);
+ case "/":
+ return divide(firstNumber, secondNumber);
+ default:
+ throw new Error(ErrorMessage);
+ }
+ })();
+};
+
+const add = (firstNumber, secondNumber) => {
+ return firstNumber + secondNumber;
+};
+
+const sub = (firstNumber, secondNumber) => {
+ return firstNumber - secondNumber;
+};
+
+const divide = (firstNumber, secondNumber) => {
+ return Math.floor(firstNumber / secondNumber);
+};
+
+const multiple = (firstNumber, secondNumber) => {
+ return firstNumber * secondNumber;
+};
+
+export default calculateValue;