Skip to content

Conversation

@seeyoujeong
Copy link

@seeyoujeong seeyoujeong commented Jul 23, 2024

배포 링크

접속

미션을 수행하면서 어려웠던 점

  • 카드 정보 추가에서 카드 별칭 추가로 넘어갈때 상태를 어떻게 가져갈 수 있을까하는 부분에서 고민을 많이 했네요. 처음에는 url에 id param의 유무로 했다가 퍼널이란걸 본 기억이 떠올라서 퍼널 패턴으로 구현했습니다.
  • 카드명과 색상 고르는 모달의 트리거를 아직 제대로 못정해서 고민이 많네요.. (지금은 카드 추가 페이지에 들어가면 바로 보입니다.)
  • Input 컴포넌트 같은 공용 컴포넌트가 완전 깡통(?) 같은 상태인데 어떤식으로 스토리북을 작성해야할지 고민을 많이하는 중 입니다.

리뷰 받고 싶은 부분 & 궁금한 점

  • 코드가 많이 지저분해서 리뷰를 받기는 좀 그렇지만 모달을 보여줄 타이밍은 언제가 가장 좋을까요?
  • 한 페이지에 상태가 많게 되면 어떻게 관리하면 좋을까요?
  • 어떤 기준으로 컴포넌트를 관리하면 좋을까요?
  • 커스텀 훅에 관한 테스트 코드를 ai의 도움을 받아 작성해봤는데 '이게 맞나?'라는 생각이 들어서 의견을 주시면 감사합니다.

Copy link

@suyeon1218 suyeon1218 left a comment

Choose a reason for hiding this comment

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

안녕하세요 찬욱님...!!! 찬욱님 코드를 보면서 리뷰를 남기기보다는 인사이트를 많이 얻을 수 있었어요! Primitive UI 를 설계하신 부분이나, 여러곳에서 반복되는 핸들러 함수들을 hooks 으로 만드신 것들이나 인상 깊게 봤습니다. 코드를 깔끔하게, 그리고 이해하기 쉽게 짤 짰다는 느낌을 받을 수 있었어요...!!

리뷰한 부분

  • 주로 변수명이 헷갈리거나 파일의 위치가 적절한지에 대해 리뷰를 남겼습니다! 폴더 구조는 저도 고민이 많은데... 준일 멘토님께서 참조하라고 주신 링크에서 atoms/molecules/organisms 순으로 컴포넌트를 레고처럼 합치는 분도 계시더라구요!! 이게 신기해서 저도 다음엔 요렇게 폴더를 분리해볼까 생각 중입니다

그외 기타

  • 지금은 Input이 state로 관리되다 보니 하나의 input만 입력해도 전체 form이 렌더링되는 걸 확인했어요. 그리고 한글 입력을 할 때도 화면상에선 렌더링이 아무 변화가 없지만 렌더링이 일어나더라구요...! React.memo를 적용해보는 것도 좋을 것 같아요!

  • 카드사 선택도 모달로 잘 분리하신 걸 보면 키패트도 잘 하실 수 있지 아늘까...?! 하고 생각이 듭니다. 찬욱님이 모달 관련으로 고민을 하셨는데 도대체 어떤 부분을 고민하신 거지? 싶었어요 (잘 작성하셔서..ㅋㅋㅋ)

}
case "UPDATE_NICKNAME": {
const { id, nickname } = action.payload;
const index = state.findIndex((cardInfo) => cardInfo.id === id)!;

Choose a reason for hiding this comment

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

그냥 index 보다는 card의 ID와 일치하는 index라는 느낌이 들면 좋겠어요...!

Copy link
Author

Choose a reason for hiding this comment

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

오 그러네요. cardId로 수정해볼게요!

Comment on lines +25 to +30
return [
...state.slice(0, index),
updatedCardInfo,
...state.slice(index + 1),
];
}

Choose a reason for hiding this comment

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

splice 메서드를 써서 다음과 같이 작성할 수도 있는데 혹시 slice를 사용하신 이유가 있으실까요?

return state.splice(index, 1, updateCardinfo);

Copy link
Author

Choose a reason for hiding this comment

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

splice는 원본값을 수정해버려서 저렇게 했습니다!

Choose a reason for hiding this comment

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

그러면 nextState를 만들어서 state를 복사해놓은 다음 splice를 쓰는 방법은 어떠실까요?! O(2N) 으로 성능면에서 좋을 것 같아요!

Copy link
Author

Choose a reason for hiding this comment

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

오 추천해주신 방법으로 코드를 수정해야겠네요! 감사합니다~

Choose a reason for hiding this comment

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

찬욱님은 따로 store를 두는 대신 CardInfo를 Context로 관리하셨군요. CardInfo가 필요한 페이지에서 자주 변경될 일도 없고, CardInfo가 아예 사용되지 않는 페이지의 렌더링 걱정을 할 필요도 없으니 Context를 사용해도 좋은 것 같아요...! 거기다 useReducer는 잘 사용하지 않는 훅인데 이렇게 구현할 수도 있구나 하는 인사이트를 얻고 가요!

Copy link
Author

Choose a reason for hiding this comment

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

추가정보를 드리면 useState도 사실 useReducer로 만들어졌다고 합니다!

Choose a reason for hiding this comment

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

오우... 역시 이론에 빠삭하세요

overflow-y: auto;
}

.page-title {

Choose a reason for hiding this comment

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

CardList 페이지에 있는 <Title /> 태그의 style이 어디 있나 찾아보려고 했는데 index.css 에 있어서 조금 헤맸어요...! 특정 컴포넌트의 style 파일만 따로 만들어두신 이유가 있으실까요?

Copy link
Author

Choose a reason for hiding this comment

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

아 특별한 이유는 없고 기존 스타일을 가져다 쓴...ㅎㅎ

Choose a reason for hiding this comment

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

우앙... 이게 바로 Primitive UI를 사용해서 만든 페이지군요...! 제가 Primitive UI가 뭔지 확실히 몰라서 막 구현했는데 많은 걸 배우고 가요...!!

Copy link
Author

Choose a reason for hiding this comment

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

아직 미완성이긴하지만 도움이 됐다니 다행입니다. :)

Comment on lines 31 to 35
const handleExpiredYear = (value: string) => {
const filteredValue = filterDigits(value);

setExpiredYear(filteredValue);
};

Choose a reason for hiding this comment

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

찬욱님 ExpiredYear 를 보고 제가 요구사항을 년도가 아니라 일수로 알고 있다는 걸 발견했습니다..... 부끄럽군요

Choose a reason for hiding this comment

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

Input 요소들은 Card와 관련이 있다기 보단 CardInfoEdit과 관련이 있어보인다는 생각이 들어요! 그럼에도 Card폴더에 넣으신 건 CardInfoEdit이 이런 Input보다 한단계 위에 있는 컴포넌트라서 그런 걸까요?

Copy link
Author

Choose a reason for hiding this comment

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

깊게 생각한 부분은 아니지만 결국 카드와 연관된 일이라고 생각해서 card폴더라고 했지만... 규모가 커지면 나누는게 좋을듯하네요!

Comment on lines +38 to +40

focusNext(e.target, (value) => value.length === 4);
}}

Choose a reason for hiding this comment

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

옆으로 넘어가는 기능을 hook으로 분리했군요...! 잘 배워갑니당

interface ValidationMessageProps {
isValid: () => boolean;
errorMessage: string;
showOnBlur: boolean;

Choose a reason for hiding this comment

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

왠지 Blur시에만 보여줄 수 있는 게 아니라 다른 상황에도 보여줄 수 있을 것 같아요...! 다른 프로퍼티 이름이 있을까요?

Choose a reason for hiding this comment

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

아니면 상단에서 isValid() && showOnBlur 를 함께 묶는 것도 좋을것 같아요~!

Copy link
Author

Choose a reason for hiding this comment

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

아 맞네요. blur에만 초점을 맞춰버렸군요. showMessage나 isShow()로 수정해보는게 괜찮겠죠?

Choose a reason for hiding this comment

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

좋은 방법이라고 생각해요!!

import { useRef } from "react";

const useFocusNext = (order: string[]) => {
const inputRefs = useRef<Record<string, HTMLInputElement | null>>({});

Choose a reason for hiding this comment

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

어떻게 관리하시나 했는데 ref를 객체로 관리하는 방법이 있군요... 👍

maxLength={cardValidator.number.maxLength}
type={index > 1 ? "password" : "text"}
value={value}
name={`num${index + 1}`}

Choose a reason for hiding this comment

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

input에 직접 name을 등록하는 방법이 있군요... 지짜 마니 알아가서 찬욱님 코드 보는 게 재밌어요

interface ValidationMessageProps {
isValid: () => boolean;
errorMessage: string;
showOnBlur: boolean;

Choose a reason for hiding this comment

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

아니면 상단에서 isValid() && showOnBlur 를 함께 묶는 것도 좋을것 같아요~!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants