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단계 - 페이먼츠] - 초코(강다빈) 미션 제출합니다. #357

Merged
merged 47 commits into from
Apr 23, 2024

Conversation

00kang
Copy link

@00kang 00kang commented Apr 18, 2024

안녕하세요 피터! 초코🍫입니다.
페어(다르)와 함께한 페이먼츠 1단계 미션 리뷰 잘 부탁드립니다. !!

🔗 배포 링크

페이먼츠 페이지

🔑 키워드 및 학습 목표

  • Component, Storybook, State, hooks
  • 재사용 가능한 Input Component를 개발한다.
  • Storybook을 사용하여 컴포넌트의 다양한 상태를 시각적으로 테스트한다.
  • 카드 정보를 효과적으로 렌더링 하기 위한 상태 관리를 경험한다.

🖼️ 컴포넌트 구조


❓ 궁금한 점

CSS 라이브러리

"스타일링에는 CSS Module, styled-components, emotion 중 한 가지를 선택하여 사용한다." 라는 조건이 있었습니다.
저희는 현재 트렌드이기도 하지만, 굳이 styled component를 사용해야 할 이유를 찾지 못해서 emotion을 선택했는데요. 현업에서는 어떤 라이브러리를 사용하는지, styled component와 emotion 중 어떤 것을 선호하는지 피터의 의견을 궁금해요.

카드 정보 중 유효기간 유효성 검사

카드 정보 중 유효기간에 입력한 날짜와 입력하는 시점의 현재 날짜를 비교할 때, 입력과 동시에 체킹해야 할지 form을 제출할 때 체킹해야 하는지 고민이 되더라고요. 일단은 form 제출시에 유효한 정보인지 확인하는 게 맞다고 판단되어 유효성 검사로 넣진 않았습니다! 어떻게 생각하시나요?

Storybook 오류

저와 페어 둘 다 Storybook이 처음이라 그런지 아래와 같은 오류가 발생했을 때 해결하지 못했어요. 주변 크루들에게도 도움을 받아보았지만 여전히 해결하지 못해 요구사항인 Storybook 작업을 하지 못한 채로 PR을 올리게 되었습니다,, 기본 세팅(npx sb init -> npm run storybook) 에서도 서버가 오픈되지 않는데 피터의 도움을 받을 수 있을까요 ㅠㅠ
스크린샷 2024-04-18 140447

더 고려할 점?

현재 미션 단위에서 더 고려해야 할 사항이 있을까요? 리팩터링할 요소나 리액트 프로젝트를 할 때 주의할 점 등 알려주세여~

00kang and others added 30 commits April 16, 2024 14:42
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
- credit card 번호 확인 유효성 검사
- credit card 유효기간 유효성 검사
- credit card 소유자 이름 유효성 검사

Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
00kang and others added 5 commits April 18, 2024 14:58
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Co-Authored-By: Lee sang Yeop <mma7710@naver.com>
Copy link
Author

@00kang 00kang left a comment

Choose a reason for hiding this comment

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

질문 남깁니다!

Comment on lines 47 to 71
<InputFormContainer>
<CreditCardForm
title={CARD_FORM_MESSAGE.inputCardNumber}
description={CARD_FORM_MESSAGE.cardNumberDescription}
type={CARD_FORM_TYPE.cardNumber}
inputValue={cardNumber}
handleChange={setCardNumber}
inputError={cardNumberError}
/>
<CreditCardForm
title={CARD_FORM_MESSAGE.inputCardExpirationDate}
description={CARD_FORM_MESSAGE.cardExpirationDateDescription}
type={CARD_FORM_TYPE.expirationPeriod}
inputValue={expirationPeriod}
handleChange={setExpirationPeriod}
inputError={expirationPeriodError}
/>
<CreditCardForm
title={CARD_FORM_MESSAGE.inputCardOwner}
type={CARD_FORM_TYPE.owner}
inputValue={owner.name}
handleChange={setOwner}
inputError={ownerError}
/>
</InputFormContainer>
Copy link
Author

Choose a reason for hiding this comment

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

반복되는 컴포넌트
정보를 입력하는 CreditCardForm 컴포넌트는 카드번호, 유효기간, 카드소유자이름 입력으로 총 3번 사용되고 있어요. 컴포넌트를 3번 호출하는 방법과 정보를 변수로 따로 저장하고 map을 이용해서 컴포넌트를 1번 호출하는 방법 중 어떤 것이 더 효율적인 걸까요? 저는 더 직관적인 첫번째 방식(컴포넌트 3번 호출)이 더 낫다고 생각했는데 피터의 생각이 궁금해요~

Choose a reason for hiding this comment

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

저도 말씀주신대로 직관성을 많이 고려하는 편입니다. 만약 map을 사용하는데, 세 컴포넌트들 사이에 분기가 많아져서 map 함수가 복잡해져 오히려 직관성을 해친다면 그냥 주루룩 나열하는 편이고, 그게 아니라 map을 사용해서 간단하게 만들 수 있다면 map을 사용하는 편인 것 같아요.

Comment on lines +1 to +8
const SIGN = {
empty: "",
slash: "/",
mask: "●",
doubleZero: "00",
};

export default SIGN;
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.

오.. 이런 네이밍은 저도 항상 고민입니다.. 좋은 방법이 있다면 제발 알려주세요..!

Comment on lines 1 to 8
import styled from "@emotion/styled";
import CreditCard from "../../components/creditCard";
import CreditCardForm from "../../components/creditCardForm";
import useInput from "../../hooks/useInput";
import CARD_FORM_MESSAGE from "../../constants/cardFormMessage";
import { CardNumberValue, ExpirationPeriodValue } from "../../@types/CreditCard";
import { CARD_FORM_TYPE } from "../../constants/cardFormType";
import SIGN from "../../constants/sign";
Copy link
Author

Choose a reason for hiding this comment

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

import 하는 게 많을 땐 eslint-import 등의 라이브러리를 사용해서 정리해야 할까요? 페어는 그냥 수동으로 스타일 파일과 코드 파일, 상수 파일 섹션으로 공백을 통해 구분을 줬는데, 사실 import문을 잘 보지 않는 것 같아 의미가 없는 것 같더라고요. 피터는 어떻게 하시나요?

Choose a reason for hiding this comment

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

페어분처럼 수동으로 정리하든, import 정리 도구를 사용하든 일단 깔끔하게 해두면 좋은 것 같아요. (근데 아마 파일이 많아지면 수동으로 정리하기는 힘드실거에요 😅) 제 경험 상으로는, auto-import를 사용했을 때 가끔 잘못 import를 하는 경우가 있는데, 그럴 때 정리가 안돼있으면 import문을 찾기가 번거롭더라구요.

Copy link
Author

Choose a reason for hiding this comment

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

import 정리 라이브러리를 설치할가 하다가, VSCode 내장 기능인 sort 기능(TypeScript: Sort Imports)을 활용해 정리해봤습니다.

Copy link

@iborymagic iborymagic left a comment

Choose a reason for hiding this comment

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

안녕하세요 초코! 미션 진행하시느라 고생 너무 많았습니다 👏👏👏
예상했던 것보다 리뷰가 더 늦어져서 죄송하다는 말씀 다시 한 번 드립니다 🙇

일단, 타입스크립트와 리액트를 열심히 활용해보고자 하는 모습이 보여서 좋았던 것 같습니다. 큰 문제 없이 잘 구현해주셨고, 약간 생각해볼거리도 몇 가지 있었던 것 같아서 관련해서 간단하게 피드백을 달아놨습니다. 확인 완료되면 다시 리뷰 요청 부탁드려요!

아래는 질문 주신 부분에 대한 답변입니다!

CSS 라이브러리

다들 이 문제로 고민이 많으신가보네요. 😅 현업에서는 둘 다 많이 사용되는 편이고, 저희는 styled-components를 사용하고 있어요. 처음 프로젝트를 만들 당시에 styled-components가 더 커뮤니티가 활발했어서(인기가 많아서) 선택한걸로 알고 있어요. (styled-components가 기능이 제한적이라 더 직관적이기도 했던 것 같아요) 요즘 들어서는 사실 막 되게 큰 차이점이 있다기보다는, emotion이 쬐끔 더 지원하는 기능이 많아서 그 기능들이 필요하다면 emotion을 사용하면 될 것 같네용

카드 정보 중 유효기간 유효성 검사

우선, form 제출 시에 유효한 정보인지 확인하는 게 맞다고 판단하신 이유가 궁금합니다. 사실 요런거는 뭐가 맞다기보다는 합당한 근거를 가지고 있는지가 더 중요하다고 생각해요. 나중에 가면 요런 문제는 기획자분들이나 동료 개발자분들과 상의를 해서 결정하게 될텐데, 그럴 때 초코만의 튼튼한 근거가 있다면
상대방을 설득하기도 더 쉬워질테니까요~

Storybook 오류

사실 에러같은 건 스스로 해결하는 경험을 쌓는 게 좋긴 합니다. 에러 메시지를 읽어봐도 모르겠으면, 당장 검색 조금만 해봐도 금방 나오는 경우가 많아요. 에러는 특히, 초코가 경험하는 에러를 이미 다른 사람들이 겪었을 가능성이 높아서, 깃헙 이슈 탭만 슬쩍 뒤져봐도 금방 나오는 경우가 많답니다. 바벨 세팅 해주니까 금방 해결되네요!

Comment on lines +40 to +58
checkCreditExpirationPeriod(value: string, name: string) {
const maxDigit = 2;
const limitValue = 12;

if (ValidatorCondition.checkMaxDigit(value, maxDigit))
return { isError: false, isValid: false };

if (!ValidatorCondition.checkIsDigit(value)) return { isError: true, isValid: false };

const isValidMonth =
name === CARD_INPUTBOX_NAME.expirationPeriod.month
? ValidatorCondition.checkIsBelowNumber(value, limitValue) &&
ValidatorCondition.checkIsNotDoubleZero(value)
: true;

if (!isValidMonth) return { isError: true, isValid: false };

return { isError: false, isValid: true };
},

Choose a reason for hiding this comment

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

유효한 expiration date인지도 함께 검사하면 좋지 않을까요? (이미 지나간 날짜인 05/21을 입력해도 통과가 되더라구요!)

Copy link
Author

@00kang 00kang Apr 22, 2024

Choose a reason for hiding this comment

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

저와 페어는 다음 항목에 대해서는 form을 제출할 때 검사해야 하는 부분이라고 생각해서 에러를 발생시키지 않았습니다!

  • cardnumber 16자리 입력하기
  • expiration date에 과거 날짜 입력하기

그런데 입력과 동시에 이를 검사해서 에러를 발생시켜야 할까요? 피터의 생각이 궁금하네용

Choose a reason for hiding this comment

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

오 form을 제출할 때 검사해야한다고 생각하신 이유가 뭘까요?

저는 아직 1단계니까, form을 제출하는 로직이 없으므로 입력할 때 검사하는 방법밖에 없다고 생각했어요. 물론 사실 요런 부분은 정책을 어떻게 가져가냐에 따라 달라지는 부분이니, 초코가 생각하시기에 합리적인 방향으로 구현하시면 될 것 같긴 합니다. 하지만 근거가 뒷받침된다면 더할 나위 없을 것 같네요.

if (Object.keys(CARD_INPUTBOX_NAME.owner).includes(name))
return this.checkCreditCardOwner(value);

return { isError: false, isValid: false };

Choose a reason for hiding this comment

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

요 isError와 isValid는 역할에 어떤 차이가 있는걸까요? (useInput을 보면 !isValid일 때 return을 해주고 있는데, 그건 isError일 때 return하는 걸로도 충분히 역할이 가능하지 않을까 싶어서요!)

Copy link
Author

Choose a reason for hiding this comment

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

isError는 에러로 인식하여 빨간색 border box와 에러 메시지를 발생시키고, isValid는 값의 유효성을 판단합니다. 예를 들어 cardNumber에서 4자리 이상을 입력하면 더 이상의 입력을 막는 것처럼이요!
그래서 isError가 false이고 isValid가 true이어야 모든 입력 조건을 잘 통과한 것으로 간주했습니다.

Choose a reason for hiding this comment

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

오호 그렇군요. 사용자에게 에러메시지로 강조해서 보여줄만한 유효성 검사는 isError로 판단하고, 그렇지 않은 유효성은 isValid로 판단한다고 받아들이면 될까요?

Comment on lines +5 to +6
const useInput = <T extends object>(initialValue: T) => {
const [inputValue, setInputValue] = useState<T>(initialValue);

Choose a reason for hiding this comment

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

제네릭까지 활용하셨네요 👍


const useInput = <T extends object>(initialValue: T) => {
const [inputValue, setInputValue] = useState<T>(initialValue);
const [inputError, setInputError] = useState<boolean>(false);

Choose a reason for hiding this comment

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

boolean 값이니, is~꼴의 네이밍이 적절할 것 같네요! inputError라고 해서, error 객체인 줄 알았어요 😅

Copy link
Author

Choose a reason for hiding this comment

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

네이밍 주의하겠습니당

return (
<CreditCardFormContainer>
<TitleWrapper>{title}</TitleWrapper>
<DescriptionWrapper>{description}</DescriptionWrapper>

Choose a reason for hiding this comment

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

DescriptionWrapper에 margin이 적용돼있네요! description이 optional value인 만큼, 이럴 때는 description이 없으면 조건부 렌더링으로 스타일을 아예 제거해주는 것이 더 좋은 것 같습니다~

<CreditCardContainer>
<CreditCardHeader>
<YellowBox />
<BrandLogoBox>{CreditCardBrandLogo(creditCardNumber[0])}</BrandLogoBox>

Choose a reason for hiding this comment

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

요 CreditCardBrandLogo는 컴포넌트 형태로 통일하지 않고, 함수 형태로 사용하는 이유가 있나용?

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 21 to 34
const sizeWidthMap = {
small: 23,
medium: 48,
large: 100,
};

const widthPercentage = sizeWidthMap[size];

return (
<Input
type="text"
value={inputValue}
onChange={handleChange}
style={{ width: `${widthPercentage}%` }}

Choose a reason for hiding this comment

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

어차피 sizeWidthMap에 퍼센트 수치를 저장해둘거면, 그냥 아예 '23%' 문자열 자체를 저장해두는 건 어떠신가용?

Choose a reason for hiding this comment

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

그리고 요 sizeWidthMap은 굳이 컴포넌트 내부에 둘 필요는 없을 것 같아요! (컴포넌트가 리렌더링될 때 불필요한 것들이 재생성되지 않게)

Copy link
Author

Choose a reason for hiding this comment

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

constants/inputBoxWidthSize.ts 로 분리해보았습니다!

}: InputCreditCardNumberProps) => {
return (
<InputContainer>
<InputLabel htmlFor="creditCardNumber">{CARD_FORM_MESSAGE.cardNumber}</InputLabel>

Choose a reason for hiding this comment

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

원래는 한 개의 input 당 한 개의 label이 권장되는 걸로 알고있는데, 그렇지 않고도 접근성을 지키고 싶다면 aria-label 혹은 aria-labelledby 를 고려해보면 좋을 것 같아요.

Copy link
Author

@00kang 00kang Apr 22, 2024

Choose a reason for hiding this comment

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

덕분에 알게 됐습니다! 감사합니다.

WAI-ARIA(Web Accessibility Initiative - Accessible Rich Internet Applications) : 웹 접근성을 향상시키기 위한 기술

  • aria-label : HTML 요소에 대한 대체 텍스트 레이블을 제공
  • aria-labelledby : HTML 요소의 레이블을 다른 요소의 텍스트 콘텐츠로 지정
  • 한 개의 input 당 한 개의 label을 연결하는 것이 접근성 측면에서 권장되지만, 여러 개의 InputBox가 하나의 레이블을 공유할 때 사용하기 좋은 속성

inputError: boolean;
}

const CreditCardForm = ({

Choose a reason for hiding this comment

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

요 CreditCardForm 컴포넌트로 인해 props drilling이 좀 더 심해지는 면이 없지 않아 있는 것 같습니다. 요럴 때는 컴포넌트 합성을 고려해보는 것도 나쁘지 않아보여요! (Payments 컴포넌트에서 아래와 같은 형태로 사용할 수 있게끔 고민을 해보시면 좋을 것 같습니다)

<CreditCardForm>
    <InputCreditCardNumber
        inputValue={inputValue as CardNumberValue}
        handleChange={handleChange}
        inputError={inputError}
    />
</CreditCardForm>

Copy link
Author

Choose a reason for hiding this comment

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

제가 아직 리액트를 잘 몰라서 정리해보았습니다!

Props Drilling

  • React 애플리케이션에서 데이터를 부모 컴포넌트로부터 자식 컴포넌트로 전달하는 과정
  • 복잡성을 증가시킬 수 있어 컴포넌트 합성을 고려할 수 있음

children을 통한 컴포넌트 합성

  • 부모 컴포넌트에서 자식 컴포넌트를 렌더링할 때 자식 컴포넌트를 children prop으로 전달할 수 있음

@00kang
Copy link
Author

00kang commented Apr 22, 2024

피터~ 초코입니다.
주말동안 아파서 이제야 리팩터링하고 리뷰요청드립니다. ㅠ
이번에도 확인해주시고 수정이 필요한 부분 혹은 추후 학습하고 개선할 수 있는 부분이 있다면 짚어주시면 감사하겠습니다!

🔗 배포 링크

페이먼츠 페이지

storybook 페이지

✅ 반영 사항별 커밋 바로가기

네이밍이나 스타일링 등의 리팩터링 이외에 주요 변경사항의 커밋링크를 남겨놓았습니다. 확인해주세요!

Storybook 서버 오픈 에러 해결

TypeScript: Sort Imports 활용해서 import문 정렬

CreditCardBrandLogo 함수에서 컴포넌트로 수정

CreditCardForm의 props drilling 해결

Storybook 서버 오픈 에러 해결

creditCard 컴포넌트 Storybook 테스트

❗ Storybook 서버 오픈 오류 해결 방안

피터가 알려준 바벨 세팅으로는 해결되지 않아 다른 방법을 시도해보았습니다!
이 오류는 TypeScript 구문을 올바르게 해석하지 못해 발생한 오류라고 보입니다. 그래서 @babel/preset-typescript를 포함함으로써 Babel이 TypeScript 코드를 정확하게 변환할 수 있게 되어, 해당 오류가 해결되었습니다.

  • 기존의 babel.rc 파일 삭제

  • babel.config.js 파일 추가

    module.exports = {
      presets: ["@babel/preset-typescript"],
    };
    

❓ 질문사항

  • 예시 코드에선 docs를 다루지 않았지만 몇몇 크루들은 docs를 사용했더라구요. 스토리북 테스트는 docs까지 작성하는 게 좋을까요? 추가로 Storybook으로 다뤄야 할 컴포넌트의 영역은 어디까지 일까요?
  • 제가 우테코를 시작하면서 웹프론트엔드 개발을 시작했기에 많은 부분이 부족합니다. 이번 미션을 통해 꼭 알아가야 할, 혹은 추가적으로 학습해 보면 좋을 키워드를 추천받을 수 있을까요?
  • 해당 미션의 학습 목표 중 다음과 같은 문구가 있었습니다. 카드 정보를 효과적으로 렌더링 하기 위한 상태 관리를 경험한다. 앞서 말했듯이 리액트 경험이 부족하다보니 효과적인 상태 관리라는 게 와닿지 않더라구요. 어떤 것을 의도한 건지, 효과적인 상태 관리를 위해 할 수 있는 건 뭐가 있을지 알 수 있을까요?

Comment on lines +50 to +60
<CreditCardForm
title={CARD_FORM_MESSAGE.inputCardNumber}
description={CARD_FORM_MESSAGE.cardNumberDescription}
inputError={cardNumberError}
>
<InputCreditCardNumber
inputValue={cardNumber}
handleChange={setCardNumber}
inputError={cardNumberError}
/>
</CreditCardForm>

Choose a reason for hiding this comment

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

Props drilling과 컴포넌트 합성에 대한 지식이 없었던 것치고, 굉장히 리팩터링을 잘해주셨는데요? 👍👍

CARD_THRESHOLD.minimumVisaNumber <= firstTwoNumber &&
firstTwoNumber <= CARD_THRESHOLD.maximumVisaNumber
)
return <CreditCardImg src={VISACARD} alt="비자카드 이미지" />;

Choose a reason for hiding this comment

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

이미지 src를 import해서 사용하는 것도 말씀을 안드렸는데 스스로 잘 해주셨네요

return (
<InputContainer>
<InputLabel id="creditCardNumberLabel">{CARD_FORM_MESSAGE.cardNumber}</InputLabel>
<InputWrapper aria-labelledby="creditCardNumberLabel">

Choose a reason for hiding this comment

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

사실 각 input에 aria-labelledby="creditCardNumberLabel"을 달아주면 좋겠다는 의도였는데, 혹시 inputWrapper에다가 달아준 이유가 있나요?

Copy link
Author

Choose a reason for hiding this comment

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

그러고 보니 신용카드 섹션 내의 인풋 각각을 인식할 수 있으려면 input마다 aria-labelledby를 달아주는 게 좋겠네요! 반영하겠습니다.

if (Object.keys(CARD_INPUTBOX_NAME.owner).includes(name))
return this.checkCreditCardOwner(value);

return { isError: false, isValid: false };

Choose a reason for hiding this comment

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

오호 그렇군요. 사용자에게 에러메시지로 강조해서 보여줄만한 유효성 검사는 isError로 판단하고, 그렇지 않은 유효성은 isValid로 판단한다고 받아들이면 될까요?

@iborymagic
Copy link

  1. 초코가 잘 판단해보시고, 이 storybook을 누군가에게 보여주는 용도로 제작한다거나 이외에 문서의 깔끔함을 유지해야하는 상황 등에서 필요하다면 docs까지 작성해주시면 될 것 같습니다.
    storybook의 범위는 사실 어떤 방식으로 개발하느냐, 어떤 용도로 사용하느냐에 따라 너무나도 달라질 수 있는 부분이라, storybook을 사용하는 대기업들이 어떻게 쓰고 있는지를 살펴보면서 고민해보시면 좋을 것 같네요.
    에어비앤비: https://airbnb.io/lunar/?path=/story/core-accordion--custom-title-component
    BBC: https://www.bbc.co.uk/iplayer/storybook/index.html?path=/story/styleguide--colours
    가디언: https://5dfcbf3012392c0020e7140b-gmgigeoguh.chromatic.com/?path=/story/layouts-standard--photo-essay-story

  2. 일단은 우테코에서 학습하는 것들에 대한 이해를 탄탄히 하는 것이 중요할 것 같습니다. 당장 교육자료에 있는 것만 해도 리액트 state, props, hooks, 폼 관리(controlled & uncontrolled input), 컴포넌트의 재사용성, 상태값 관리, 리렌더링 최적화, 테스트 등등 파고들려면 하나만 파고들어도 시간이 부족한 것들 투성이니까요. 요번 단계는 리액트 학습이 핵심인 것 같으니, 리액트에 관해 공부를 심도 있게 해보시면 좋을 것 같네요.
    리액트에 관해서는, https://react.dev/learn 요 문서의 'LEARN REACT' 파트만큼 알찬 학습 자료를 본 적이 없습니다.
    주변 크루들과 해당 문서를 읽는 스터디를 진행한다던가 하면 꽤나 도움이 되지 않을까 싶어요.

  3. 사실 효과적인 상태관리 라는 게 조금 추상적인 표현이라 의미가 충분히 와닿지 않을 수 있습니다만, 아마 불필요한 리렌더링이 발생하지 않게끔 최적화하라는 정도로 이해하면 되지 않을까 싶어요. 리렌더링을 왜 최적화해야 하는지에 대한 부분이 잘 와닿지 않는다면, 리액트 컴포넌트의 lifecycle(생명주기) 부터 한 번 공부해보시는 것을 추천드립니다.

Copy link

@iborymagic iborymagic left a comment

Choose a reason for hiding this comment

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

안녕하세요 초코! 리뷰 반영해주시느라 고생 많았습니다.
아마 리액트를 처음 써보신 것 같은데, 제법 리뷰를 훌륭하게 잘 반영해주신 것 같습니다.
아주 간단하게 추가 질문 달아놨으니 확인해주시고, 리뷰가 잘 반영되었으니 1단계는 이만 여기서 마무리하도록 하겠습니다.
(+ 코멘트로 질문에 대한 답변도 달아놨습니다)
고생하셨어요~

@iborymagic iborymagic merged commit b617bd3 into woowacourse:00kang Apr 23, 2024
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.

None yet

2 participants