LikeLion-FE-React-Project04 / project-repo

멋쟁이사자처럼 프론트엔드 스쿨 4기에서 Final Project로 진행한 Karly입니다.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

[FEATURE] 경고창 모달 만들기

SeoMiYoung opened this issue · comments

📝 TASK 개요

경고창 모달 공용 컴포넌트를 만듭니다.
또한, 커스텀훅을 만들어서, 경고창 모달 공용 컴포넌트를 불러올 때 항상 반복적으로 불러와야 하는 코드를 축소시켰습니다.

📚 경고창의 두가지 버튼 타입

  1. onlyConfirm: 확인 버튼만 존재
  2. confirmAndCancel: 확인/취소 버튼 존재

🤔 경고창이 어디에 사용되나요?

-------------------------------[ 버튼 타입: onlyConfirm ]-------------------------------
1. 회원가입 페이지
   - 이메일
      - 이메일을 입력하지 않음 => "이메일을 입력해주세요"
      - 옳바르지 않은 이메일 형식 입력 => "이메일 형식으로 입력해주세요"
      - 이메일을 옳바르게 입력 => "사용 가능한 이메일 입니다."
      - 이미 존재하는 이메일을 입력 => "이미 존재하는 이메일입니다."
   - 비밀번호
      - "최소 10자리 이상 입력"
      - "영문/숫자/특수문자(공백 제외)만 허용하며, 2개 이상 조합"
   - 비밀번호 확인
      - "동일한 비밀번호를 입력"
   - 이름
      - "2자리 이상 입력"
   - 휴대폰
      - 입력 안하거나, 옳바른 형식 X => "휴대폰 번호를 입력해주세요."
   - 주소
      - 주소 입력 안함 => "주소를 입력해주세요."
   - 생년월일
      - "생년월일을 다시 확인해주세요."
      - "태어난 월을 정확하게 입력해주세요"
      - "태어난 일을 정확하게 입력해주세요"
   - 이용약관동의
      - "이용약관을 확인해주세요."

2. 상품문의
   - 비밀글에 접근하면, "비밀글입니다."

3. 상품문의/후기 팝업창
   - 로그인하지 않은 사용자가 후기/문의 작성을 시도하면, "로그인하셔야 본 서비스를 이용하실 수 있습니다."

----------------------------[ 버튼 타입: confirmAndCancel ]----------------------------
1. 장바구니 페이지
   - 장바구니에 담긴 일부 상품을 삭제하려고 X버튼을 누를 때, "삭제하시겠습니까?"

👏 접근성 고려

모달창 접근성 고려해서는 이미 앞에서 여러번 글을 쓴 적 있습니다.
같은 맥락으로 진행되니, 참고하세요.

  • 메인 모달창 접근성
  • 디테일 상품 후기/문의 팝업창 접근성

❓ 사용방법

[STEP1] useAlertBox.js 커스텀 훅을 불러옵니다.

예시) import { useAlertBox } from '../../../components/AlertBox/@hook/useAlertBox';
=> 어느 파일에서 불러오냐에 따라 경로가 달라지므로, 주의해주세요!

[STEP2] useAlertBox()가 반환하는 settingAlertBox함수를 가져옵니다.

=> settingAlertBox함수를 사용해서, 경고창을 어떻게 띄울 지 세팅해 줄 것입니다.

따라서, settingAlertBox함수를 사용하기 위해, 경고창을 사용하고자 하는 컴포넌트 내부에 다음 코드를 넣어줍니다.
const { settingAlertBox } = useAlertBox();

[STEP3] showAlertBox를 호출함으로써, 경고창을 사용할 것 이므로, 다음 함수를 넣어줍니다.

// 어떤 경고창을 띄울 지 세팅하기
const showAlertBox = (getValue) => { 
   settingAlertBox(getValue);   // 경고창 세팅
};

[STEP4] 경고창을 띄우고자 하는 곳에서 showAlertBox()를 호출합니다.

  • (필수)라고 써진 key값은 반드시 설정해줘야 합니다.
  • (선택)이라고 써진 key값은 필요없으면, 안넣어줘도 됩니다.
showAlertBox({
   alertText: '',          // (필수) [경고창 텍스트 설정]
   moveUrl: '',          // (선택) [이동 할 url 설정] 만약에 '확인'버튼을 눌렀을 때, 어디론가 페이지를 이동시키고 싶은 경우만 넣어주기
   btnUiType: '',          // (필수) [버튼 형태 설정] 확인 버튼만 있는 'onlyConfirm' 또는, 확인/취소 버튼이 있는 'confirmAndCancel'을 넣어주기
   product: {},          // (선택) [어떤 상품을 삭제할 것인지 설정] cart페이지에서 경고창을 이용 할 경우, 삭제할 상품 넣어주기
});
  • 사용 예시) ProductInquiry.jsx와, ReviewTitleContainer.jsx에서의 사용
showAlertBox({
   btnUiType: "onlyConfirm",
   alertText: "로그인하셔야 본 서비스를 이용하실 수 있습니다.",
   moveUrl: '/SignIn',
}); 

✍️ useMemo와 useCallback을 적용해서 성능을 높힐 수 있을까?

팀원분께서 useAlertBox.js를 useMemo/useCallback을 써서, 성능을 높히면 어떻겠냐는 의견이 나왔습니다.
의견을 적극적으로 반영하여 다음과 같이 코드를 수정했습니다.

Before 코드...(바뀐 부분만)

const initialValueOfMove = {
   needToMove: true,
}
  
const initialValueOfRemove = {
   needToRemove: true,
}

After 코드...(바뀐 부분만)

const initialValueOfMove = useMemo(() => ({
   needToMove: true,
}), []);

const initialValueOfRemove = useMemo(() => ({
   needToRemove: true,
}), []);

✅ intialValueOfMove와 initialValueOfRemove에 useMemo를 적용시킨 이유?

initialValueOfMove와 initialValueOfRemove는 불필요하게 매번 생성되는 것을 방지하기 위해 useMemo를 사용했습니다. initialValueOfMove와 initialValueOfRemove는 항상 같은 값을 가지므로, 새로 생성할 필요가 없기 때문입니다.

현재 initialValueOfMove와 initialValueOfRemove의 경우, 컴포넌트 내에서 객체를 저장하고 있습니다.
객체의 경우, 원시(Primitive)타입이 아니라 객체(Object)타입이므로, 컴포넌트가 랜더링 될 때마다 같은 객체값을 넣어줘도, 항상 새로운 값을 넣어준 것 처럼 인식이 됩니다.

무슨소리냐면,

const nation1 = "Korea"   
const nation2 = "Korea"   

원시타입의 경우 이렇게 두번 호출되었을 때, nation1 == nation2는 성립하지만,

const nation1 = { nation: "Korea" }
const nation2 = { nation: "Korea" }

이건, nation1 != nation2 가 됩니다.
왜냐하면 객체타입의 경우, 메모리상의 다른 주소에 저장되기 때문입니다.

따라서 해당 커스텀훅(useAlertBox)이 계속 호출될때마다, 객체값이 재할당되는데, 그때의 객체는 같은 내용이 들어가지만, 항상 새로운 메모리 주소에 할당되서, 결국 다른 객체값으로 인식하게 됩니다.

이런 불필요한 재할당을 막기 위해 useMemo를 사용했습니다.

✅ initialValue에 useMemo를 적용하지 않은 이유?

바뀐 코드를 보면, initialValueOfMove, initialValueOfRemove에는 useMemo를 적용시켰지만, initialValue에는 적용시키지 않은것을 확인 할 수 있습니다. 물론, initialValue도 객체값을 저장하고 있긴 하지만, intialValue의 경우, 함수 외부에서 선언되고 있기 때문에 어짜피 함수가 재호출 될때마다 다시 할당되지 않습니다. 따라서 initalValue의 경우 useMemo를 적용시키지 않아도 됩니다.

✅ useCallback을 쓸 필요가 없다고 판단한 이유?

useMemo와 useCallback은 컴포넌트를 최적화하기 위한 대표적인 훅들입니다.
useMemo는 값을 메모이제이션하여 같은 값이 계산되지 않도록 하고, useCallback은 콜백 함수를 메모이제이션하여 같은 함수를 재사용합니다.
그러나, 경고창 커스텀훅(useAlertBox.js)에서는 함수를 사용한다기 보다는, settingAlertBox함수를 반환하는 구조로 되어 있어 useCallback을 사용할 필요는 없습니다.

✅ 무분별한 useMemo, useCallback의 사용은 좋지 않습니다.

useMemo, useCallback을 사용한다는 건, 값이나 콜백함수를 재활용하기 위해서, 따로 메모리를 소비해, 저장을 하겠다는 소리입니다. 그렇기 때문에, 불필요한 것까지 모두 memoization을 해버리면, 오히려 성능이 악화될 수 있다는 점을 명심해야 합니다.

  const setAlertModalState = useSetRecoilState(alertModalState); 
  const setAlertModalText = useSetRecoilState(alertModalText);
  const setAlertModalMoveState = useSetRecoilState(alertModalMoveState);
  const setAlertModalUiType = useSetRecoilState(alertModalUiType);

팀원께서 반복되는 호출을 커스텀훅으로 빼면 어떻겠냐는 의견이 나왔습니다.
시간의 여유가 되면 고려해보겠습니다.

팀원께서 useMemo나 useCallback을 적용시키면 어떻겠냐는 피드백이 나왔습니다.

최적화를 잘 공부하셨네요. ^^