프로젝트 조각 회고록 : 마지막 + 피드백

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

1/5(금)

한 것

  1. 결제등록 모달 은행 로고 넣기
  2. 찜 목록 url 제대로 나오게

1/6(토)

트러블 슈팅

블록 스코프와 전역 스코프

  1. 상황 : 리덕스 reducer 작성 중
  2. 발생 : switch-case문에서 case가 다르면 위에서 객체구조 분해한 변수 사용 불가
  3. 원인 : switch-case문은 if-else문과 마찬가지로 블록 스코프
  4. 해결 : 각 케이스별 선언(or let 키워드 사용)

💡 블록스코프와 전역 스코프는 반의어다. 전자는 대개 중괄호로 감싼 코드 블록을 말한다. if-else문, switch-case문을 그 예로 들 수 있다. 그러나 중괄호를 생략한다고 전역 스코프가 되는 것은 아니다.

블록 스코프와 엇비슷한 개념이 함수 스코프다. 그 이름에서 보이듯 function 키워드로 감싼 중괄호를 말하는데, 이 또한 별도의 스코프가 생겨서 함수 내부의 변수는 함수 밖에서 사용할 수 없다. 그러려면 return 등 외부로 꺼내는 작업이 필요하다.

여러 모달을 동시에 사용할 때

모달과 토글은 함께 쓰일 수밖에 없는 짝꿍이다. 모달 하나만 쓸 땐 단순하지만, 여러 모달을 동시에 보여주고 없애려다보면 문제가 발생할 수 있다.

  1. 의도 : 모달1 발생 -> 모달1 사라짐과 동시에 모달2 발생
  2. 상황 : 의도와 달리 모달1이 사라지기만 하고 모달2는 생기지 않음
  3. 시도 :
        if (response.data.result) {
          setToggleState();
          // TODO : 등록되었습니다 모달 왜 안 나옴
          onModal();
        }

...

        {modal && (
          <>
            {console.log('hi')}
            <ModalBasic
              type="confirm"
              content="등록"
              toggleState={true}
              setToggleState={onModal}
            />
            {console.log('after')}
          </>
        )}

우선 토글 기능을 하는 modal이 동작하는지 알아보려고 첫번째 콘솔을, 모달 컴포넌트가 렌더링되는지 보려고 두번째 콘솔을 찍었다.

그런데 hi만 찍히고 after는 찍히지 않았다! 개발자도구도 살펴보니 모달 컴포넌트가 아예 없다. onModal 하나만 실행해보니 이건 또 제대로 동작한다.

첫번째 모달이 실행되자마자 두번째 모달을 실행되는 문제라면, setTimeout을 사용해보자.

  1. 해결 :
        if (response.data.result) {
          onModal();
          setTimeout(() => {
            setToggleState((prevState) => !prevState);
          }, 2000);
        }

같은 CSS인데 크기가 다를 때

  1. 상황 : 똑같은 컴포넌트 파일이라서 요소 구성 다 같은데 크기가 다름
  2. 원인 : 글자 길이(width)에 맞춰 전체 크기가 달라진 것
  3. 해결 : text를 감싼 컨테이너의 width 고정
        .productCard {
          margin: 0 25px 40px;
          max-width: 400px;
          width: 20vw; // <-- 크기 고정
          background-color: #f5f5f5;
          border-radius: 5px;
          box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
          cursor: pointer;
          display: flex;
          flex-direction: column;
          
          h4 {
            padding: 10px;
            color: #333;
            width: 100%; // <-- 상위 요소의 100% 차지
            overflow: hidden;
            display: -webkit-box;
            -webkit-box-orient: vertical;
            -webkit-line-clamp: 2;
            text-overflow: ellipsis;

            @include responsiveText(18px, 14px);
          }

1/7(일)

배움

객체의 key를 Member.key로 하고 싶을 때

.로 객체의 key를 타고 들어가는 거니까 객체 내 객체로 만들어주면 된다.

    const formattedReviews = reviews.map((review) => ({
      review: review.review,
      title: review.title,
      isAnonymous: review.isAnonymous,
      stars: review.stars,
      boardId: review.Board.boardId,
      memberId: review.Member.memberId,
      createdAt: review.createdAt,
      updatedAt: review.updatedAt,
      Member: {
        nickname: review.Member.nickname,
      },
    }));

트러블 슈팅

//App.js
...
function App() {
  return (
    <BrowserRouter>
      <Navbar />
      <Routes>
        <Route exact path="/" element={<Main />} />
...
      </Routes>
	  <Footer />
    </BrowserRouter>
  );
}

export default App;
  1. 상황 : Navbar처럼 각 컴포넌트에 적용할 필요 없이 App.js에서 설정하려고 했는데 요소가 계속 겹쳐서 같은 방식을 쓸 수 없었다.

  2. 해결 : fixed하지 않고, 그냥 보통의 컴포넌트처럼 페이지마다 컴포넌트에 넣어뒀다.

.footer {
  margin: var(--header-margin) 0;
  width: 100%;
  padding: 20px;
  text-align: center;
  font-size: 12px;
  opacity: 0.6;

  .footerContent {
    max-width: 800px;
    margin: 0 auto;
  }
}

수직 스크롤바 고정

  1. 상황 : 뷰포트 높이보다 컴포넌트 높이가 크면 자동으로 스크롤바가 생긴다. 근데 데이터가 적은 페이지는 다른 라우터로 이동할 때마다 스크린이 움찔대는 버그가 발생했다.
  2. 해결 :
body {
  overflow-y: scroll;
  }

useEffect와 setTiemout은 언마운트를 꼬옥

  1. 의도 : 탈퇴 클릭 시 모달 1 -> 모달 2 -> 모달 1, 2 사라짐과 동시에 라우터 이동
  2. 상황 : 모달 1이 사라지자마자 라우터 이동
  3. 원인 : useEffect 내 setTiemout 함수 언마운트 누락
  4. 해결 :
  useEffect(() => {
    let timeoutId;

    if (type === 'confirm') {
      timeoutId = setTimeout(() => {
        disableModal();
      }, 3000);
    }

    return () => {
      clearTimeout(timeoutId);
    };
  }, [toggleState]);

타임아웃 함수는 언마운트 할 때 비워주지 않으면, 이전에 사용한 함수가 그대로 남아있다. 고로 설정한 시간(3초)가 되기 전에 이미 실행되었다고 간주했던 것이다.

유저 플로우가 또 다른 중요한 이유

  1. 상황 : 하위 컴포넌트에 state 변경된 값이 아닌 초기값이 전달
  2. 원인 : UI 불확실 -> 데이터바인딩 어떻게 할지 갈팡질팡 -> 백/프론트 코드 꼬임
  3. 해결 : UI 통일(결제정보 모달 -> 수정 클릭 -> 정보입력 모달) 후 양측 코드 고침
// 서버 컨트롤러
exports.findAccount = async (req, res) => {
  try {
    const targetMemberId = req.params.memberId;
    const member = await Member.findOne({
      where: { memberId: targetMemberId },
    });

    // 결제정보 없음
    if (!member.accountNum || !member.bankName) {
      return res.send({
        result: false,
        userData: { accountNum: '등록 정보 없음',
                   bankName: '등록 정보 없음' },
      });
      // 결제정보 있음
    } else {
      return res.send({
        result: true,
        userData: { accountNum: member.accountNum,
                   bankName: member.bankName },
      });
    }
  } catch (err) {
    console.error(err);
    res.status(500).send('서버 에러');
  }
};
// MyPage.js

  // 이미 등록된 결제 정보 확인
  const hasAccountCk = async () => {
    const response = await axios({
      method: 'get',
      url: `${process.env.REACT_APP_DB_HOST}${endpoint}`,
    });

    if (response.data) {
      onAccountToggle(); // 모달 1(결제정보 내역) show
      const data = response.data.userData;
      setAccountInfo({ // 데이터 세팅
        accountNum: data.accountNum,
        bankName: data.bankName,
      });

      if (response.data.result) {
        return true; // 토글로 사용
      } else {
        return false;
      }
    }
  };

...

<div
      className={`myAccount ${
                 accountToggle ? 'slideIn' : 'slideOut'
                }`}
      onClick={hasAccountCk}
      >
      결제정보 등록/확인 >
      </div>
      {accountToggle && (
      <ModalAccount
      accountInfo={accountInfo}
      setToggleState={onAccountToggle}
      setAccountInfo={setAccountInfo}
      />
)}

이어서 또 다른 문제.

  1. 상황 : 결제정보가 없는 유저는 '등록 정보 없음'을 보여주려 했는데 NULL이 기입
  2. 원인 : DB 테이블 기본값은 문자열 NULL
  3. 해결 : 결제정보 확인 컨트롤러에서 빈값이 아닌 'NULL'로 조건 걸기
    if (member.accountNum === 'NULL' || member.bankName === 'NULL')

아쉬운 점

리액트의 관건은 컴포넌트 재사용이라고 생각해서 이미 사용 중인 컴포넌트를 최대한 재사용하고 싶었다. 그래서 다른 팀원이 만든 Review 컴포넌트의 일부를 ReviewList로 컴포넌트화 했다.

두 페이지에 같은 컴포넌트를 사용할 수 있게 하려다보니 공통적으로 쓰이는 함수와 변수들이 보였고, 이를 커스텀 훅으로 만들었다. 그러고서 기존 코드에 맞춰 데이터바인딩 하려 했으나.. 수정/삭제 기능 앞에서 말짱 도루묵이 되었다.

💡 이유를 모르겠다고 쓰려던 찰나 갑자기 가설 하나가 떠올랐다! 필요한 컴포넌트를 덜 가져와서 데이터는 있는데 바인딩되지 않았던 게 아닐까?!

이게 맞다면, 댓글 수정/삭제 기능이 안 된 미스테리도 풀린다. 내일 해봐야지!!


1/8(월)

한 것

  1. 리뷰 컴포 태그 요소 제대로 가져와서 커스텀훅 적용 시도
  2. 모달 애니메이션 적용(언마운트 실패)
  3. 반응형 : 댓글, 모달, input 등

1/9(화)

한 것

  1. BE) 닉네임, 이메일, pw 변경 로직 완료
  2. 은행 로고 사진 에러 fix
  3. 전체 컴포넌트 Footer
  4. Navbar, SearchResult, CategoryResult 반응형
  5. 채팅 목록 UI
  6. 채팅방 UI + 이미지 보여주기
  7. 회원 프로필 패턴으로 변경

트러블 슈팅

은행 로고 window에서는 안 뜸

  1. 상황 : 맥에서는 보이는 사진이 윈도우에서 안 보임
  2. 확인 : 경로는 맞음
/static/bankLogo/금융아이콘_SVG_KB.svg
  1. 원인 : 한글 인코딩 문제
/static/bankLogo/ㄱㅡㅁㅇㅠㅇㅇㅏㅇㅣㅋㅗㄴ_SVG_KB.svg

해결 :
encodeURIComponent에 전체 경로를 넣어주어 해결

<img
	src={`/${encodeURIComponent(
     bankData.logoBasePath + bank.logoPath
     )}`} />

이미지 파일 화면에서 안 보임

  1. 원인 : 한글 파일은 window에서 인코딩 작업 필요
  2. 해결 : encodeURIComponent 메서드 사용
<div className="chattingBoardOne">
    <img
  src={`${
       process.env.REACT_APP_DB_HOST
      }static/userImg/${encodeURIComponent(boardInfo.image)}`}
  alt="board img"
  />
</div>

프로젝트 피드백

이렇게 프로젝트 기간이 끝나고, 지난 목요일에 발표 후 피드백을 들었다.

  • 시도한 건 이유를 곁들여 넣기

Good

  • 기술적인 발표 느낌 (화면 정의서)
  • ERD, API 명세서 있음
  • 회고록, 트러블 슈팅 꼼꼼해 보임
  • 소켓 통신 매끄러움

Bad

  • 채팅을 대변하지 못하는 아이콘(키보드) 사용
  • 불명확한 기획 : 파일이 아닌 텍스트라면 결제 기준이 무엇일지 알 수 없음

그리고 다른 팀들 발표를 보면서 마지막 3차 프로젝트엔 무엇을 더하면 좋을지 생각해봤다.

참고사항

  • 일정 관리, 프로젝트 관리 :
    구글 시트 등 문서 파일을 활용한 팀들이 확실히 꼼꼼한 확인이 가능해 보였다.

  • 보안 서버(https) 사용

  • sns 로그인 :
    레퍼런스로 참고한 사이트 대다수가 간편 로그인을 지원 중이었다.

  • 업데이트 계획 :
    업데이트 할 수 있다는 건 그만큼 토대가 잘 짜여졌기 때문에 덧댈 수 있는 거라고 본다.

  • scss + .module -> styled component로 사용하는 방법도 있다.

  • 백드롭 필터 :
    CSS 설정 중 하나인데, hover랑 같이 쓰면 예쁠 것 같다.

끝! 나긴 했는데...

  • sass를 제대로 구조화해서 사용할 수 있어 좋았다.

    • 하지만 클래스명을 매번 새로 작성하려니 번거롭기 그지 없다. tailwindcss는 유틸리티 css라서 클래스명을 따로 만들지 않아도 된다는데 한번 써보고 싶다.
  • 라이브러리나 프레임워크를 거의 안 쓴 것도 아쉽다. 하물며 API로 가져오는 작업도 안 했으니.. 다양한 라이브러리를 사용해 보고 싶다.

  • 🐞 :

    • 채팅 스크롤바를 하단으로 고정하면 브라우저의 스크롤바도 같이 움직임
    • 내 리뷰가 2개 이상이면 테이블 개수 자체가 늘어남
  • 더 많이 배우고 싶다.. 💪

profile
일단 해보는 편
post-custom-banner

0개의 댓글