[코딩온] 프로젝트 조각 회고록 : 4~6일차

Yunhye Park·2024년 1월 1일
0
post-thumbnail
post-custom-banner

12/29(금)

한 것

  • 마이페이지 UI + hover 시 밑줄 효과
  • 계좌번호 필드 위치 변경
    • 회원가입 시 계좌번호 받으면 처리는 간편하지만 너무 많은 정보를 한번에 입력해야 해서 피로도가 높을 것 같다.
    • 그래서 옵션값으로 지정했지만 보안에 취약한 느낌을 줄 것 같아 판매글 작성 시 모달창 활용하자고 제안해봐야겠다.
  • utility.scss 추가 (button)
  • 회원가입 & 로그인 서버 요청 및 전달 받기

트러블 슈팅

git pull = git fetch + git merge

  1. 발생 : 내가 로컬 브랜치를 커밋한 때 remote에서 다른 팀원이 merge
    → 우선 로컬 develop으로 pull
    → 로컬 브랜치에서 pull 받으려는 중

  2. 오류 메시지 :

hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint: 
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint: 
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.
  1. 원인 : git pull = git fetch + git merge 라서 머지할 방식을 고르라는 것

1) fast-forward only

  • 원격저장소에 새 commit이 있고, 로컬에는 없을 때.
  • 로컬에는 새 commit이 있고, 원격저장소에는 없을 때.

둘 중 한 곳에만 commit이 있을 경우 pull을 허락한다. 원격과 로컬 모두 새 commit이 있다면(=원격저장소에서 pull을 받아오지 않고 로컬에서 새 커밋을 했다면) git pull이 불가하다.

pull 받아야 해서 이 옵션은 기각.

2) rebase
커밋 히스토리 정리에 자주 쓰이는 명령어다. 원격 브랜치의 마지막 commit으로 로컬 브랜치의 상태를 되돌린다.

되돌릴 것 없이 그냥 합치기만 되어서 패스.

3) merge
말 그대로 브랜치끼리 합친다. git pull 받을 때 merge commit이 필수. 이 방식을 선택했다.

  1. 해결 : git config pull.rebase false 터미널 입력
    → merge 커밋 메시지 작성
    git push origin 로컬 브랜치명
    (이때 수동 처리하는 것이므로 UNIX 화면이 잠시 나온다 Shift + :wq로 exit)
    → remote에서 PR

git config로 지금 리포에선 merge가 기본 옵션으로 적용되었다.

fetch는 비동기x2 처리

  1. 발생 : fetch 요청 후 서버에서 전송 받은 데이터가 Promise {<pending>} (= 아직 처리 중)
  2. 원인 : fetch는 json파일로 변경 필수인데, 이것도 비동기 처리해야 함
  3. 해결 : const res = await response.json()

화면 테스트 및 피드백

  • 마이페이지

  • 회원가입 후 로그인 후 메인 화면

🐞 엔터키 적용하자
🐞 로그인 실패 시 안내 문구 보여주기


12/30(토)

한 것

오늘은 거의 회원가입, 로그인 컴포넌트들만 수정했다.

  • fetch → axios로 변경
  • 슬라이드 애니메이션 추가
  • 회원가입 시 아이디, 닉네임 중복 체크 기능
    ㄴ각각 성공/실패를 화면에 어떻게 보여줄지 로직 고민
  • FIX : 회원가입 유효성 에러 메시지 사라짐 해결

트러블 슈팅

useForm : 로그인 빈값 인식 문제

  • 의도 : 로그인 시 id, pw의 input이 빈값 아닐 때만 버튼 동작
  • 문제 : watch 함수로 필드 값을 추적함에도 어떤 값이든 빈값으로 인식
  • 원인 : watch는 비동기 처리하기 때문에 렌더링 중에는 동작 안 함
  • 해결 :
const [isFormValid, setIsFormValid] =useState(false);
const idValue = watch('id');
const pwValue = watch('pw');

useEffect(() => {
  const isIdValid = idValue.trim() !== '';
  const isPwValid = pwValue.trim() !== '';
  const isFormValid = isIdValid && isPwValid;
  setIsFormValid(isFormValid);

}, [idValue, pwValue]);

useEffect를 사용하면 특정 시점에 특정 동작이 가능하도록 로직을 설계할 수 있다. 그래서 id와 pw의 value가 바뀔 때마다 각각의 값이 빈값인지 확인(isIdValid, isPwValid)하고 두 필드 모두 빈값이 아닐 때만 true를 반환하도록 한다.

버튼에 해당 내용을 disabled 조건으로 걸어두면 완료.

<button
type="submit"
className="signButton"
disabled={!isFormValid}
>
  로그인
</button>

이렇게 해결되는 줄 알았으나, 또 다른 문제가 발생!

1-2. trim 타입 에러

Cannot read properties of undefined (reading 'trim')
TypeError: Cannot read properties of undefined (reading 'trim')
  • 원인 :
    trim 메서드는 기본적으로 문자열 양끝의 공백을 제거한다. 그런데 idValuepwValue에 문자열이 들어가는지 알 수 없어서 타입 에러가 발생했다.
  • 해결 :
const idValue = watch('id') || '';
const pwValue = watch('pw') || '';

기본값으로 빈 문자열이 들어가도록 설정해주면 문제가 해결된다.

💡 이 에러를 만나고, 타입스크립트의 필요성을 느꼈다. 이 라이브러리를 이미 사용했더라면 이런 에러를 만날 일이 없지 않았을까.

이렇게까지 했는데도 여전히 빈값으로 인식한다.

1-3. register 함수

  • 원인 : useForm의 register를 단어 뜻 그대로 가입 시에 사용하는 함수로 여김

하지만 그게 아니었다. register가 포함된 input을 useForm에서 값을 추적해 업데이트(watch) 등 동작하는 거였다. 로그인 할 땐 유효성 검사를 거치지 않아서 에러 원인을 찾는 데 애먹었다. 😓

  • 해결 : 로그인 input에 {...register("name", ...)} 등록

2. 회원가입 유효성 에러 메시지 사라짐

하도 회원가입과 로그인 부분을 옮겨 가며 작업하다보니 어느 시점에서부터 문제가 발생한 것인지 파악하기 어려웠다. 그래서 삽질 시작.

  • 디버깅 :
    1) DB 생성됨 (서버 측 문제 아님)
    2) 유효성 검사는 동작 중 (useForm 관련 코드는 문제 없음)
    3) 개발자도구에 에러 메시지 발생 시 생기는 태그(<small>) 안 생김

즉 동작은 하고 있으나, 화면에 표시되지 않는 문제였다. 그 이유를 못 찾다가 다른 작업 도중, 아이디/닉네임 중복 체크 버튼을 클릭하면 유효성 메시지가 확인되는 것이다!

  • 원인 :
  • 해결 :
  const handleInputChange = async (fieldName, value) => {
    // 값 업데이트
    setValue(fieldName, value);

    // 유효성 검사 실행
    await trigger(fieldName);
  };

...
<input
type="text"
onChange={(e) => handleInputChange('id', e.target.value)}
...
/>

리액트의 onChange 이벤트는 기본적으로 두 글자를 입력해야 한 글자를 인식한다. 즉 input의 변화에 한 발 느리게 동작한다. 유효성 검사하기엔 치명적이라서 useForm에서 제공하는 함수를 이용해 수동으로 값을 변경하기로 했다.

그래서 setValue로 입력한 값으로 해당 필드 값을 변경하고, trigger 함수를 사용해 수동으로 유효성 검사를 실시했다.

API 명세서의 중요성

  1. 발생 : 로그인 아이디/닉네임 중복 버튼 클릭 시 서버에 데이터 보내려는 중
  2. 오류 메시지 :
AxiosError: Request failed with status code 400
  1. 원인 : 백에서 받는 형식과 다르게 데이터 가공
  2. 해결 : 백 코드에 맞춰 {type(id or nickname): value} 로 요청

💡 이때 type을 매개변수로 받았는데, 객체의 key를 매개변수로 받으려면 대괄호를 덧대어 준다.

const data = { [key]: value };

소감과 배움

  • API 명세서가 중요하다는 걸 몸소 느꼈다. 무엇보다 Req, Res를 잘 정해두는 게 좋다고 느꼈다. 그래야 백에 넘길 데이터를 어떻게 가공할지 생각할 수 있다. 백도 마찬가지일 테고.

    • 그러면서도 배운 게 있는데, 두 개의 input을 하나의 로직으로 처리할 땐 type으로 구분해서 전달해야 FE에서 처리하기 좋다. id와 닉네임 각각을 중복 처리하지만 사실 백에서는 처리 과정이 거의 동일하다.

    • 그래서 엔드포인트 하나로 값만 구분하여 처리를 해줬는데, 프론트에 전달할 땐 각각 어떤 필드에 대한 처리인지 type을 전달해줘야 '중복된 아이디/닉네임입니다'를 화면에 보여주기 용이하다.


12/31(일)

한 것

오늘은 회원가입/로그인 예외처리에 집중했다.

[회원가입]

  • 아이디 & 닉네임 중복 확인 OK여야 회원 가입 가능
    • 중복 발생 → 안내 메시지
  • 아이디 유효성 검사 통과해야 중복 체크 하도록
    • 유효성 에러 → 중복 발생으로 간주
  • 엔터키 동작

[로그인]

  • 엔터키 동작

배움

변수를 사용해 객체 key를 만들려면

case 1. key가 곧 변수일 때

setMsg((prev) => ({ ...prev, [type]: true }));

대괄호로 묶는다.

case 2. key의 일부가 변수일 때
객체 key는 따옴표 없는 문자열로 작성된다. 즉 문자열과 변수를 함께 쓰는 것과 같으므로 백틱을 사용해준다.

setMsg((prev) => ({
  ...prev,
  [`${type}Duplicate`]: '❌',
}));

유효성 검사 통과 기준을 무엇으로?

중복 체크 시 유효성 검사 여부도 확인해야 한다. 유효성 검사는 통과하지 못했는데 중복이 아니라고 간주해 잘못된 싸인을 넘길 수 있어서다.

무엇을 기준으로 유효성 검사 여부를 파악할까 고민하다가 에러 객체를 활용했다.

  const handleCheck = async (type, value) => {
    try {
      if (errors.id) {
        setMsg((prev) => ({
          ...prev,
          [`${type}Duplicate`]: '❌',
        }));
      } else {
        const data = { [type]: value };
        const response = await axios.post(
          'http://localhost:8000/member/checkDuplicate',
          data
        );
        // 이후 요청 응답 처리

💡 유저 관점에서 예외처리 하기

아이디, 닉네임 중복 확인을 하지 않았을 경우 회원가입 버튼이 disabled된다면 개발하는 입장에선 편하다. 추가로 예외처리할 게 없다.

하지만 유저 입장에선 유효성검사에 맞게끔 모든 값을 채웠는데도 회원가입 버튼이 활성화되지 않아 오류처럼 보일 수 있다. 그래서 유효성검사만 통과해도 회원가입 버튼은 활성화하되, 안내 메시지로 중복 확인을 유도했다.

함수의 반환값이 함수일 때

엔터키 동작 구현에 특이점이 있었다. 바로 handleSubmit 함수에 onSubmit 함수를 매개변수로 전달한다는 점.

  const handleEnter = (e) => {
    if (e.key === 'Enter') {
      handleSubmit(onSubmit)();
    }
  };

handleSubmit 함수를 호출해서 새 함수를 반환한다. 그 함수(반환된 새 함수)를 호출하는 역할로 ()이 필요한 것이다.

트러블 슈팅

💡 state는 비동기 함수

1️⃣ 비동기 처리할 때 useEffect
1. 발생 : 값 업데이트 될 때마다 콘솔로 확인 중인데 업데이트가 바로 안 됨
2. 원인 : state 변수는 비동기 함수이므로 업데이트 되기 전에 콘솔이 찍힐 수 있음
3. 해결 :

  useEffect(() => {
    console.log('signUpCk updated:', signUpCk);
    console.log('msg updated:', msg);
  }, [signUpCk, msg]);

useEffect로 확인하고 싶은 값이 변할 때마다 콘솔에 찍어서 원하는 대로 동작하는지 확인할 수 있었다.

소감

  • 어제 type을 서버에서 보내줘서 화면에 보여줄 수 있었지만, 결과 텍스트가 긴 게 안 어울렸다. 그래서 OX로 표기만 하는 것으로 마무리했다. 데이터를 처리할 때와 화면의 보일 그림을 생각할 때가 참 다르단 걸 느꼈다. 이걸 잘 이해해야 다른 부서와의 소통이 원활해질 테다.
profile
일단 해보는 편
post-custom-banner

0개의 댓글