
Owhat!은 OTT 플랫폼 별 채널에서 사용자들이 정보를 공유하고, 소통할 수 있는 OTT 통합 커뮤니티입니다.
약 4주간 진행된 첫 번째 팀 프로젝트가 끝났다.
제대로 된 협업 경험이 없었기 때문에 팀 프로젝트는 데브코스에서 가장 기대하는 부분이었다.
생각대로 되지 않는 것도 많았고 부족함도 많이 느꼈지만, 그만큼 많은 것을 배울 수 있는 시간이었다.

우리팀은 공통 컴포넌트를 분류해 나름대로의 디자인 시스템을 만들었다.
아무래도 UI 프레임워크를 사용하는 것보다 번거롭고, 담당한 컴포넌트 중 퀄리티가 아쉬운 부분도 있었다.
그렇지만 직접 컴포넌트를 개발해 본 경험, 강의에서 JS로 구현한 컴포넌트를 TS로 구현해 본 경험이 의미있었다!
이렇게 공통 컴포넌트를 개발해놓고 가져다 쓰니 이후 페이지를 만들 때 작업 시간이 훨씬 단축되기도 했다.
학교에서 했던 프로젝트에서는 코드 컨벤션도 정하지 않았고, 코드 리뷰도 하지 않았다😂 지금 생각해보면 정말 말도 안 된다..
Type alias와 Interface 중 어떤 경우에 어떤 방식을 쓸지부터 Eslint/Prettier 설정, 디렉토리 구조, 커밋 메시지 규칙, PR/Issue 템플릿까지 정하고 협업을 시작했다. 팀장님이 평소 쓰시던 방식을 들고 오셔서 빠르고 편하게 정할 수 있었다👍
중간중간 더 세밀히 정해야 하는 부분이 생겼었지만, 확실히 틀이 있으니 혼선이 덜하고 컨벤션이 갖춰진 느낌이었다.
PR은 승인을 받아야 merge할 수 있도록 했다.
리뷰를 하면서 직접 개발하지 않은 부분이 어떻게 구현되었는지 살필 수 있었고, 리뷰를 받으면서 구현할 때 미처 생각하지 못한 개선점을 알 수 있어 좋았다.
같은 맥락에서 다른 팀원 분들의 PR에 달린 리뷰에서도 배울점이 정말 많았다.
Tailwind는 기본적으로 같은 CSS 속성을 다루는 스타일의 우선순위가 고정되어 있다. 일반 CSS를 사용할 때처럼 뒤에 적힌 스타일이 적용되는 것이 아니라 Tailwind에서 정해준 우선순위에 따라 적용되는 것이다.
그렇기 때문에 의도치 않은 문제가 일어날 수 있는데, twMerge를 사용해 해결할 수 있다.
import { ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
export const cn = (...inputs: ClassValue[]) => {
return twMerge(clsx(inputs));
};
위처럼 유틸 함수를 만들어 사용하면 된다.
하지만 tailwind.config.js에 정의한 커스텀 속성을 사용할 땐 제대로 적용되지 않았는다는 한계가 있었다. 해당 링크에 tailwind-merge 개발자가 제시한 해결법이 있지만, 시간에 쫓겨 프로젝트에 적용해보지는 못했다😓
Axios 인스턴스를 만들면 반복적으로 사용되는 config를 한번에 설정하고 가져다 쓸 수 있다.
export const instance = axios.create({
baseURL: `${BASE_URL}:${PORT}`,
headers: {
'Content-Type': 'application/json',
},
});
처음엔 Authorization도 넣어줬는데 토큰 값을 불러오지 못하는 경우가 있었다. 이 부분은 팀원 분께서 interceptors를 사용하여 로그인/로그아웃 시 토큰 값이 들어가고 제거되도록 수정하셨다.
사용자 더보기 페이지를 구현할 때, 부모 요소 hover 시 배경색을 지정했을 때, 자식 요소 hover 시에는 부모 요소 배경색이 변하지 않게 하고싶었다.

부모 요소(탭 목록에 있는 유저 Item)를 클릭하면 메시지 전송 페이지로 이동하고 자식 요소(팔로우 버튼)를 클릭하면 페이지 이동 없이 팔로우, 언팔로우가 실행되는데, 두 경우가 완전히 다른 로직을 실행하기 때문이다.
부모 요소 선택자:has(자식 요소 선택자)와 같이 쓰면 부모 요소가 자식 요소를 갖고 있을 때, 명시한 CSS 속성을 적용시킬 수 있다.
Tailwind로는 부모 요소 className에 다음과 같이 쓸 수 있다.
hover:bg-gray-200 hover:has-[button:hover]:bg-transparent

⚠️ 지원 브라우저 확인
상당히 최근에 추가된 문법이라 구형 브라우저에서는 작동하지 않을 수 있다.
공통 컴포넌트에서 Textarea를 담당했다.
댓글이나 메시지 작성 시 인스타그램 DM 작성과 동일하게 작성하는 내용 길이에 따라 Textarea가 일정 크기까지 늘어났다가 내용을 삭제하면 다시 줄어드는 기능을 구현하고 싶었다.
검색했을 때 많이 나오는 방식대로 구현했는데, 리뷰를 받으며 문제점을 알게 되었다.

스타일을 직접 변경하지 않고 textarea 기본 속성인 rows를 활용하고 싶었지만, 내용을 일부 삭제했을 때 textarea.style.height = auto를 쓰지 않고 내용에 맞게 줄어들게 하는 방법을 찾지 못했다.
결국 height 변경 부분을 아예 빼버렸고, 한 줄로 쭉 댓글과 메시지를 입력해야 하는 답답한 경험을 제공하게 되었다..😂 이 부분이 너무 아쉬워서 계속 고민하고 시도해보려 한다!
사실 커피챗 때 멘토님을 통해 처음 알았을 정도로 해당 라이브러리에 대해 무지했다.
제대로 공부하고 쓰고 싶었고, 나름 공식문서도 살펴봤지만 결국은 냅다 써버렸다..🥲
다른 팀원 분들이 구현한 코드를 많이 참고하며 쓰다보니 원하는 대로 동작하지 않을 때 원인을 파악하지 못해 제대로 대응할 수 없었다.
사용자 더보기 페이지에서 팔로우/팔로우 취소 버튼 기능을 구현할 때, refetch가 제대로 이루어지지 않는 문제를 겪었다. refetch를 명시적으로 실행해도 해결되지 않았다.
결국 팀원분께 도움을 청했고, 팔로우/팔로우 취소 요청을 보낼 때 invalidateQueries에 queryKey를 잘못 지정하여 생긴 문제라는 걸 알았다.
아직 queryKey 개념을 명확히 이해하고 있지 못한 것 같다. 두 번째 팀 프로젝트 시작 전까지 Tanstack Query를 열심히 익혀야겠다.
프로젝트 꼼꼼히 기록하기
React, Tanstack Query, 합성 컴포넌트 공부하기
프로젝트 기간에 매일 코드 리뷰 시간을 정해두고 실행하기