Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[1단계 - 페이먼츠] 유세지(김용래) 미션 제출합니다. #81

Merged
merged 47 commits into from
May 3, 2022

Conversation

usageness
Copy link

@usageness usageness commented Apr 28, 2022

안녕하세요, 리뷰어님! 이번 페이먼츠 미션을 진행하게 된 유세지입니다.

리액트도, CDD도 경험이 거의 없다시피 하여 코드가 많이 부족한걸 느끼고 있습니다.
모자란 실력만큼 페어나 다른 크루들끼리 많은 이야기를 나누며 진행하게 되어 한 편으로는 즐겁기도 하네요.

구현은 데모 페이지🔗 를 확인해주시길 바랄게요!
이번 미션 잘 부탁드립니다 😊

도출한 필수 요구 사항

입력 폼 구현사항

  • 카드 번호는 반드시 입력해야 한다.
    • 입력은 숫자만 가능하다.
    • 뒤 8자리는 password type이다.
  • 만료일은 반드시 입력해야 한다.
    • 입력은 숫자만 가능하다.
    • 월 입력은 1 이상 12 이하여야 한다.
    • 년 입력은 00 이상 99 이하여야 한다.
    • 숫자가 한 자리수일 경우 앞에 0을 포함해야 한다.
  • 카드 소유자 이름을 입력할 수 있어야 한다.
    • 이름의 길이는 1 이상 30 이하여야 한다.
  • 보안 코드는 반드시 입력해야 한다.
    • 입력은 숫자만 가능하다.
    • 보안 코드의 길이는 3자리여야 한다.
    • 보안 코드는 password type이다.
  • 카드 비밀번호는 반드시 입력해야 한다.
    • 입력은 숫자만 가능하다.
    • 카드 비밀번호는 password type이다.

카드 Preview

  • 각 입력 폼에 입력을 할 때 마다, 카드 Preview에 입력 사항이 반영되어야 한다.
  • 카드의 종류에 따라 카드 Preview의 배경색이 변해야 한다.

카드 선택 모달 창

  • 카드 번호를 모두 입력하면, 카드 선택 모달 창이 보인다.
  • 모달 창에서 카드의 종류를 선택할 수 있다.
  • 카드의 종류를 선택하면 모달 창이 사라진다.

프로젝트 기본 구조

image

가장 작은 InputBasic 컴포넌트를 InputBox로 감싸 입력 공간을 만들고,
이를 입력받는 종류에 따라 ~Form 과 같은 래핑 컴포넌트를 만들었습니다.
이렇게 만든 컴포넌트들은 CardRegisterPage 라는 페이지 단위 컴포넌트 내부에 배치하였습니다.

아쉽거나 미심쩍은 부분

useRef?

여러개의 input을 받는 래핑 컴포넌트는 이전 input을 모두 입력시
자동으로 다음 input에 포커싱이 되도록 구현하였습니다.

useRef를 이용하면 요소에 접근할 수 있다고 하여 바로 사용해 보았는데,
DOM에 직접 접근하는 방식이다 보니 생성해서 뿌려(?)주는 리액트에서는 상당히 이질적으로 느껴졌습니다.

자연스럽지 않다고 생각되지만 마땅한 대안이 없어 그대로 사용하였는데,
혹시 이러한 직접 참조를 개선 할 만한 방법이 있을까요?

스토리북

사실 원활한 Component driven develop을 위해 스토리북을 사용했어야 했는데,
미션을 막상 진행해보니 적극적으로 활용하진 못했던 것 같습니다.
도구 자체에 대한 이해도 부족과 시간적 여유가 부족했던게 가장 큰 이유였던 것 같네요 😥

아직까지는 작은 단위의 UI 요소들부터 만들때 도움이 될 것 같다는 막연한 생각만 갖고 있는데
실제 개발 프로세스에서는 스토리북을 어떤 식으로 활용하는지 궁금합니다.

  • 추가로 현재 스토리북이 react 18 버젼과 충돌하는 것 같은데 혹시 다들 겪고 계신 이슈이신가요..?

스타일 컴포넌트?

페어와 미션을 처음 시작하며 했던 논의 중 컴포넌트를 만들어야 할 이유에 대해 이야기를 나누었었는데,
저는 컴포넌트가 가진 속성 중 재사용성에 초점을 두어 "재사용 불가능한 컴포넌트는 존재 의의가 없다." 라고 생각 했었습니다.

그 자체로 어느정도 의미나 재활용 가능한 기능이 있어야 컴포넌트로서의 의의가 있다고 느꼈는데,
이후에 styled-component를 사용하며 단순히 스타일만 선언된 컴포넌트가 과면 의미가 있을까? 라는 고민을 하게 되었습니다.

리액트에서 컴포넌트를 분리해야 할 기준으로 어떤걸 고려하면 좋을까요?
혹시 이에 대한 개발자들의 공통적인 생각이나, 리뷰어님만의 특별한 기준이 있으신가요?


익숙하지 않은 도구들도 써보고 하려니 평소보다 많이 헤맸던 미션이었습니다.
이상한 부분은 따끔하게 지적해주시면 감사하겠습니다!

kwannee and others added 30 commits April 26, 2022 14:28
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Co-authored-by: YongRae_Kim <kyr9389@naver.com>
Copy link

@austinpark420 austinpark420 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 유세지!
만나서 반갑습니다 😄
코드 관련해서 코멘트 남겨놨습니다. 확인 부탁드릴게요!!
추가로 UI상 카드번호를 입력한 다음 카드를 선택한 후, 카드번호를 지우게되면 기본카드 UI으로 변경되어야 할것 같습니다!

useRef?
여러개의 input을 받는 래핑 컴포넌트는 이전 input을 모두 입력시
자동으로 다음 input에 포커싱이 되도록 구현하였습니다.
useRef를 이용하면 요소에 접근할 수 있다고 하여 바로 사용해 보았는데,
DOM에 직접 접근하는 방식이다 보니 생성해서 뿌려(?)주는 리액트에서는 상당히 이질적으로 느껴졌습니다.
자연스럽지 않다고 생각되지만 마땅한 대안이 없어 그대로 사용하였는데,
혹시 이러한 직접 참조를 개선 할 만한 방법이 있을까요?

이질적이라고 생각하실 필요는 없을 것 같습니다! 제가 알고있기로는 일반적으로 사용하는 방식이라고 생각합니다.

스토리북
사실 원활한 Component driven develop을 위해 스토리북을 사용했어야 했는데,
미션을 막상 진행해보니 적극적으로 활용하진 못했던 것 같습니다.
도구 자체에 대한 이해도 부족과 시간적 여유가 부족했던게 가장 큰 이유였던 것 같네요 😥
아직까지는 작은 단위의 UI 요소들부터 만들때 도움이 될 것 같다는 막연한 생각만 갖고 있는데
실제 개발 프로세스에서는 스토리북을 어떤 식으로 활용하는지 궁금합니다

아무래도 시간적인 여유가 부족해서 더 그렇게 생각하시는것 같네요ㅠ 제 개인적인 경험을 말씀드리면 특정 누군가가 UI를 만들어 스토리북에 배포하면 다른 사람들이 UI 코드 내부 구현된 부분에 대해서는 알필요없이 필요한 UI만 가지고 와서 사용하는 용도로 쓰고 있습니다.

추가로 현재 스토리북이 react 18 버젼과 충돌하는 것 같은데 혹시 다들 겪고 계신 이슈이신가요..?

yarn으로 설치하시거나 package.json에서 storybook 관련 dependency를 모두 삭제하고 npm install 한 후에 npx sb init 로 스토리북 초기화 해도 마찬가지일까요? 보내주신 링크에 댓글이 달려있던데 그 방법도 시도해보시면 좋을 것 같습니다.

스타일 컴포넌트?
페어와 미션을 처음 시작하며 했던 논의 중 컴포넌트를 만들어야 할 이유에 대해 이야기를 나누었었는데,
저는 컴포넌트가 가진 속성 중 재사용성에 초점을 두어 "재사용 불가능한 컴포넌트는 존재 의의가 없다." 라고 생각 했었습니다.
그 자체로 어느정도 의미나 재활용 가능한 기능이 있어야 컴포넌트로서의 의의가 있다고 느꼈는데,
이후에 styled-component를 사용하며 단순히 스타일만 선언된 컴포넌트가 과면 의미가 있을까? 라는 고민을 하게 되었습니다.
리액트에서 컴포넌트를 분리해야 할 기준으로 어떤걸 고려하면 좋을까요?
혹시 이에 대한 개발자들의 공통적인 생각이나, 리뷰어님만의 특별한 기준이 있으신가요?

컴포넌트를 어떻게 관리할지에 대한 고민은 결국 확장성과 유지보수에 대한 고민이라고 생각합니다. 그렇기때문에 단순히 스타일만 선언된 컴포넌트라고 재사용되는 부분이 많다면 컴포넌트로 따로 관리하는게 더 좋은 방법이라고 생각합니다.

Comment on lines 4 to 10
import { CardExpireDateInputForm } from "../components/CardRegister/CardExpireDateInputForm";
import { CardNumbersInputForm } from "../components/CardRegister/CardNumbersInputForm";
import { CardOwnerInputForm } from "../components/CardRegister/CardOwnerInputForm";
import { CardPasswordInputForm } from "../components/CardRegister/CardPasswordInputForm";
import { CVCInputForm } from "../components/CardRegister/CVCInputForm";
import { CardSelectModal } from "../components/CardRegister/CardSelectModal";
import { CVCHelperModal } from "../components/CardRegister/CVCHelperModal";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 디렉토리구조는 ../components/cardRegister인데 코드에서는 ../components/CardRegister 으로 되어있네요...
로컬서버 구동이 되었을까요?
추가로 CardRegister 디렉토리에 index 파일을 만들어서 import문을 줄이는 방법도 좋을 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

디렉토리를 생성할때는 이름이 CardRegister 이었는데...
페어의 레포지토리에서 다시 클론받고 푸시하면서 대소문자가 바뀌게 된 것 같아요... ㅠㅠ
소문자로 통일해주었습니다!

index 파일을 만들어 한번에 임포트 하니 깔끔해졌네요! 감사합니다 😊

});

const checkerFactory = (subject) => {
const key = subject;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

임시변수 key가 꼭필요한가요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

필요하지는 않지만 인자로 받은 subject 값을 key로 사용한다는 의미로 넣었었습니다.
하지만 다시 생각해보니 코드 상으로 key 자리에 들어가 있어 굳이 두 번 설명한다는 느낌이네요.
변수 선언은 제거해 주었습니다!

Comment on lines 69 to 75
const checkerFactory = (subject) => {
const key = subject;

return (isCompleted) => {
setCheckInputs((prev) => ({ ...prev, [key]: isCompleted }));
};
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

checkerFactory함수명으로는 역할을 유추하기 어려운 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Input에 유효한 값이 모두 들어왔는지 확인하는 check 변수 중 각 state에 해당하는 checker를 골라주는 함수이므로
setCheckInputStateOf(state) 로 변경해주었습니다!

{modalVisible && loadModal()}
</Modal>

<Button disabled={allCompleted ? false : true}>다음</Button>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disabled 처리를할 때 삼항연산자가 꼭 필요할까요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Button 컴포넌트에서 children을 사용하지않고 disabled이 props를 만들어서 사용하는 방법 한번 고려해봐도 좋을 것 같습니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

disabled 처리는 삼항연산자까지 갈 필요없이 간단하게 !allCompleted 로 할 수 있었네요!

Button 컴포넌트에서는 children을 사용하지 말고 disabled 처럼 props로 확인 같은 내용을 넘겨주는게 좋다는 말씀이실까요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

좋다기보다는 그런 방법은 어떠신가 의견을 드렸습니다. 아래코드와 같이 작성하게되면 닫는 태그를 사용하지 않아도 되서요 😄

<Button disabled={allCompleted ? false : true} value={"다음"} />

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Button 태그의 경우는 이미지나 다른 컴포넌트도 버튼으로 만들 수 있도록 염두했던 컴포넌트여서
value props을 전해주게되면 확장성이 떨어질것 같다고 느꼈어요.
피드백을 받고 나니 너무 큰 그림을 그렸다는 생각도 조금 드네요 😅

Comment on lines 115 to 118
<CardText>{ownerName ? ownerName : 'NAME'}</CardText>
<CardText>
{expireDate.month ? expireDate.month : 'MM'}/
{expireDate.year ? expireDate.year : 'YY'}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삼항연산자가 꼭 필요할까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음.. 확실히 return 문 안에서 삼항연산자를 빼주었더니 return 문 내부는 깔끔해진 느낌이에요!

대신 컴포넌트 내부에서 변수로 선언해주고, 그 변수를 불러오도록 수정했는데
이렇게 하면 결국 코드의 양이 늘어나서 이전보다 좋아진 것인지 잘 와닿지 않는 것 같아요.

리뷰어님께서는 삼항 연산자가 가독성 측면에서 많이 차이가 난다고 보시나요?
저는 코드를 직접 작성해서 그런지 처음 보았을때의 느낌을 잘 모르겠어요 😥

const cardOwnerName = ownerName || "NAME";

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

어떻게 삼항 연산자를 제거할 수 있을까 고민하며 이러한 방법도 시도해 보았는데요,

export const Card = ({
  cardType,
  cardNumbers,
  expireDate = { year: "YY", month: "MM" },
  ownerName = "NAME",
  handleModalVisible,
}

컴포넌트의 props에서 초기 값을 주더라도 호출하는 쪽에서 빈 값을 넘겨주게되면
위에서 설정한 값이 아닌 빈 스트링 값 ''으로 넘어오게 되어 정상적으로 작동하지 않았습니다.
Card.defaultProps 를 이용해도 결과가 달라지지 않아 결국
const cardOwnerName = ownerName || "NAME" 으로 처리하게 되었습니다.

혹시 이런 경우엔 빈 값이나 null이 오더라도 삼항연산자 없이 지정한 값을 사용할 수 있는 방법이 있을까요?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래와 같이 표현하는 쪽에서 변경이 가능합니다!!!
{expireDate.month || 'MM'}/{expireDate.year || 'YY'}

handleCardExpireCheck,
}) => {
const handleMonthInput = (e) => {
if (isNaN(e.nativeEvent.data) || parseInt(e.target.value) > 12) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 if문의 역할이 어떤건지 알 수 있을까요?

Copy link
Author

@usageness usageness May 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

카드 만료일의 입력이 숫자가 아니거나, 12를 넘어가면 입력되지 않도록 하는 역할입니다!
처음에 1이 들어오는 경우는 두 번째 숫자에 따라 10, 11, 12 월이 들어올 수 있으니 다음을 고려해서 우선 입력을 받되,
다음으로 들어오는 값이 3이상이면 들어올 수 없게 하였습니다.

src/index.js Outdated
@@ -0,0 +1,11 @@
import React from 'react';

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

react를 사용하는데 파일 확장자가 js이네요..?

Copy link
Author

@usageness usageness May 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗... jsx로 수정했습니다!


export const CardOwnerInputForm = ({ ownerName, handleOwnerNameInput }) => {
const handleOwnerNameChange = (e) => {
if (e.target.value.length > 30) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

input의 maxLength 속성을 이용해도 좋을 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

맞습니다! 이곳뿐 아니라 전반적으로 form 태그나 Input 태그에서 기본적으로 제공하는
validation 방법들을 사용하지 못하고 있다는 느낌을 받았어요.

이번 피드백 기간이나, 다음 step에서는 html에서 할 수 있는 작업은 최대한 html에서 진행하고,
js에서는 js로만 할 수 있는 작업을 하는 방향으로 코드를 수정해보려고 합니다!

flex-direction: column;
align-items: center;
`;
const CardBottom__number = styled.div`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bem 방식이 섞여있는 걸까요?

Copy link
Author

@usageness usageness May 2, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

미션에서 기본으로 제공했던 템플릿이 BEM 방식을 사용하고 있어
그대로 옮겨오는 과정에서 처음엔 템플릿의 형식을 따라갔었습니다.

프로젝트 전체적으로 보니 일관성이 없어 보여서 컴포넌트로 통일 하도록 할게요!

backgroundColor: "",
});

const [modalVisible, setModalVisible] = useState("");

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modalVisible의 담당하는 역할이 컴포넌트 노출여부와 어떤 컴포넌트를 보여 줄지 2가지인것 같은데 네이밍을 보고 유추하기 좀 어려운것 같습니다! 추가로 이 부분을 커스텀 훅으로 빼보는것도 좋을 것 같습니다.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modalVisibleState와 modalName 두 가지로 분리하였습니다!
추가로 useModal 이라는 커스텀 훅으로 분리해보았는데 코드가 줄어들거나 하지는 않네요 😂

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 모달을 많이 사용하게된다면 확실히 코드가 주는걸 알 수 있을거에요! 그리고 훅을 사용하는 입장에서 훅 구현부에 대해서 학습없이 리엑트에서 제공해주는 훅처럼 사용하면 되니 편하게 사용하실 수 있을거에요!

@airman5573
Copy link

  • 추가로 현재 스토리북이 react 18 버젼과 충돌하는 것 같은데 혹시 다들 겪고 계신 이슈이신가요..?

https://github.com/storybookjs/storybook/releases
나와있는대로 npx sb@next upgrade --prerelease 해서 6.5.0-beta.1`로 업그레이드 하니까 해결 되었습니다!

@usageness
Copy link
Author

usageness commented May 2, 2022

안녕하세요, 오스틴 😊

이번에 말씀해주셨던 피드백들을 반영하고, 추가적인 기능도 구현해 보았는데
잘 이해가 되지 않는 부분이 있어서 코멘트로 남겼습니다. 확인해주시면 감사하겠습니다!

1. 커스텀 훅
커스텀 훅도 이번에 처음 사용해보았는데, 뭔가 반복적인 작업이라고 할만한게 크게 없어서
코드 길이가 줄어들거나 하진 않았지만 모달창이 많아진다면 편하게 추가하고 관리할 수 있을 것 같습니다.
이 부분은 더 공부를 해볼게요 :)

2. props drilling
step2에서 context API 를 필수적으로 사용해야하기 때문에 지금은 일부러 사용하지 않고,
props drilling으로 인해 생기는 불편을 경험해보려 했는데
확실히 뎁스가 깊어질수록 생각해야할게 많아질 것 처럼 보이네요.
상위 컴포넌트에서 관리해야하니 그만큼 컴포넌트가 뚱뚱해지는것도 있구요.

3. 스토리북
스토리북도 최신 버젼으로 업데이트 하고, 빌드 및 배포를 마쳤습니다. 아래 링크에서 확인하실 수 있어요!
상호작용 테스트는 아직 감이 잡히지 않고 있지만... 다음 스텝에선 최대한 개선해보겠습니다!
( 코멘트 남겨주셔서 고마워요 병민! @airman5573 )

스토리북 페이지 📕
데모 페이지 🔗

꼼꼼한 리뷰 감사드립니다!
다음 과정에서도 잘 부탁드릴게요 👍

Copy link

@austinpark420 austinpark420 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

안녕하세요 유세지!
코멘트 반영한 부분 확인했습니다. 😄
질문 주신 부분에 대해서 답글과 수정하신 코드에 대해서 코멘트 남겨놨으니 확인하시고 step2에 반영할 부분이 있으면 반영해주시면 될것 같습니다.

step1 진행하시느라 고생 많으셨습니다!!

height: 150px;
`;

export const CVCHelperModal = () => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modal이라기보단 보통 tooltip이라고 해요.

Comment on lines +14 to +18
useEffect(() => {
const isCVCCompleted = CVC.length === 3;

handleCardCVCCheck(isCVCCompleted);
}, [CVC]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의미파악이 어렵지 않다면 임시변수는 최대한 지양하는게 좋을것 같습니다!

Comment on lines +12 to +38
const handleMonthInput = (e) => {
if (isNaN(e.nativeEvent.data) || parseInt(e.target.value) > 12) {
return;
}

if (e.target.value.length === 3) {
e.target.value = parseInt(e.target.value);
}

if (e.target.value.length === 1) {
e.target.value = '0' + e.target.value;
}

if (e.target.value === '0' || e.target.value === '00') {
e.target.value = '00';
}

handleExpireDateInput((prev) => ({ ...prev, month: e.target.value }));
};

const handleYearInput = (e) => {
if (isNaN(e.nativeEvent.data) || e.target.value.length > 2) {
return;
}

handleExpireDateInput((prev) => ({ ...prev, year: e.target.value }));
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validation을 따로 함수로 만든다면 handleMonthInput의 로직이 좀 더 눈에 잘 들어올 것 같습니다!

name && setModalName(name);
};

return [modalVisibleState, setModalState, modalName];

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확장성을 위해 배열보다는 객체 형태로 return하시는게 좋을 거에요!

@austinpark420 austinpark420 merged commit e0804f1 into woowacourse:usageness May 3, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants