GDSC KNU 활동을 하면서 FE 1팀에 속해 React 스터디 진행 중에 만든 과제이다.
이런 것도 토이 프로젝트일까 싶다만은 딱히 분류 게시판이 없어성.......
제한 조건은 다음과 같았다.
- React를 이용할 것
- 휴대폰처럼 '-' 등장하도록 할 것
- 일정 글자 이상 시 제출 버튼 활성화 및 색상 변경
- 제출 버튼 클릭 시 페이지가 이동하고 입력한 값을 띄울 것
- Container-Presenter 패턴 사용할 것
Container-Presenter 패턴
화면에 보여지는 UI인 Presenter와 데이터를 처리하거나 실질적인 처리를 하는 Container를 분리하여 만드는 패턴
src
│ App.js
│ index.js
│
├─components
│ BottomButton.js
│ BottomButton.module.css
│ Button.js
│ Button.module.css
│
└─routes
Numpad.js
NumpadPresenter.js
NumpadPresenter.module.css
Result.js
Result.module.css
src 파일의 구조는 다음과 같다.
components라는 폴더에서 Button 컴포넌트를 만들었고
routes 폴더에서 페이지 단위로 js파일을 만들어서 구성하였다.
import { useState, useEffect } from "react";
import NumpadPresenter from "./NumpadPresenter.js";
function Numpad() {
const [input, setInput] = useState("");
const [btn_disabled, changeDisabled] = useState(true);
useEffect(() => {
const countHypen = input.match(/-/g) == null ? 0 : input.match(/-/g).length;
const inputLen = input.length - countHypen;
if (inputLen < 4) {
setInput(input.replace(/-/g, ""));
changeDisabled(true);
}
if (inputLen >= 4 && inputLen < 8)
setInput(input.replace(/-/g, "").replace(/(\d{3})(\d)/, "$1-$2"));
if (inputLen >= 8 && inputLen < 10) {
setInput(
input.replace(/-/g, "").replace(/(\d{3})(\d{4})(\d)/, "$1-$2-$3")
);
changeDisabled(true);
}
if (inputLen === 10) {
setInput(
input.replace(/-/g, "").replace(/(\d{3})(\d{3})(\d{4})/, "$1-$2-$3")
);
changeDisabled(false);
}
if (inputLen === 11)
setInput(
input.replace(/-/g, "").replace(/(\d{3})(\d{4})(\d{4})/, "$1-$2-$3")
);
if (input.length > 13) setInput(input.replace(/-/g, ""));
}, [input]);
const onClick = (event) => {
setInput((current) => current + event.target.value);
};
const onReset = () => {
setInput("");
};
const onDelete = () => {
setInput(input.substring(0, input.length - 1));
};
return (
<NumpadPresenter
input={input}
onClick={onClick}
onReset={onReset}
onDelete={onDelete}
onDisabled={btn_disabled}
></NumpadPresenter>
);
}
export default Numpad;
핵심이 되는 Numpad.js의 코드이다.
Container-Presenter 패턴에서 Container 부분이라고 할 수 있다.
input이라는 state를 만들어서 useEffect로 input을 감시하게 만든 다음,
숫자 버튼을 클릭하면 onClick으로 input을 업데이트하고
input이 바뀔 때마다 길이를 계산해서 정규표현식으로 형식에 맞도록 수정해주었다.
input 길이를 '-' 문자를 뺀 길이로 계산해서 추가나 삭제 상관없이 형태가 변하도록 짰다.
아마 처음에 onChange를 썼었는데 길이 계산에서 JS의 비동기 처리로 인해 한박자 느리게 처리가 되었어서
해결 방법을 찾아다 useEffect를 사용했었던 것으로 기억한다.
import Button from "../components/Button";
import BottomButton from "../components/BottomButton";
import styles from "./NumpadPresenter.module.css";
import { Link } from "react-router-dom";
function NumpadPresenter({ input, onClick, onReset, onDelete, onDisabled }) {
return (
<div className={styles.wrapper}>
<div className={styles.screen}>{input}</div>
<div>
<Button btn_value="1" onClick={onClick}></Button>
<Button btn_value="2" onClick={onClick}></Button>
<Button btn_value="3" onClick={onClick}></Button>
</div>
<div>
<Button btn_value="4" onClick={onClick}></Button>
<Button btn_value="5" onClick={onClick}></Button>
<Button btn_value="6" onClick={onClick}></Button>
</div>
<div>
<Button btn_value="7" onClick={onClick}></Button>
<Button btn_value="8" onClick={onClick}></Button>
<Button btn_value="9" onClick={onClick}></Button>
</div>
<div>
<Button btn_value="*" onClick={onClick}></Button>
<Button btn_value="0" onClick={onClick}></Button>
<Button btn_value="#" onClick={onClick}></Button>
</div>
<div>
<BottomButton
onClassName="normal"
btn_value="❌"
onClick={onReset}
onDisabled={onDisabled}
></BottomButton>
<Link to={`/result/${input}`}>
<BottomButton
onClassName="call"
btn_value="📞"
onDisabled={onDisabled}
></BottomButton>
</Link>
<BottomButton
onClassName="normal"
btn_value="🔙"
onClick={onDelete}
onDisabled={onDisabled}
></BottomButton>
</div>
</div>
);
}
export default NumpadPresenter;
NumpadPresenter.js의 코드이다.
보면 알겠지만 Container와 달리 화면에 보여지는 html 코드가 Presenter에 존재한다.
'토이프로젝트 > 기타' 카테고리의 다른 글
[python] HWPtoPDF 프로그램 (0) | 2022.02.21 |
---|---|
[python-opencv] 동영상 프레임 추출 프로그램 (0) | 2022.02.21 |