목차
- 프로젝트 개요
- 트러블 슈팅 및 해결 사례
- 아쉬운 점과 스스로 잘했다고 생각한 점
- 시간 관리와 학습 과정
- 프로젝트 성과와 주요 개선점
- 결론
프로젝트 개요
이번 주 기간 동안 저는 팀과 함께 맛집 공유 뉴스 피드 사이트 프로젝트를 진행했습니다. 이 프로젝트의 목표는 사용자들이 맛집 리뷰를 작성하고 공유할 수 있는 플랫폼을 만드는 것이었습니다. 프로젝트는 React로 프론트엔드를, Supabase로 백엔드와 데이터베이스를 구축하는 방식으로 진행되었습니다.
프로젝트의 주요 기능은 다음과 같습니다:
- 사용자 인증: 회원가입, 로그인, 로그아웃 기능
- 맛집 게시물: 맛집 리뷰 작성, 수정, 삭제 기능
- 리뷰 작성 및 조회: 게시물에 대한 리뷰 작성 및 조회 기능
- 팔로우 기능: 게시물 작성자 팔로우 기능
- 마이 페이지: 사용자 프로필 수정 및 게시물 조회 기능
- 실시간 데이터 업데이트: 실시간 데이터베이스 연동
https://github.com/HOT6-FoodCode/FoodCode-Project/tree/main
트러블슈팅 및 해결 과정 및 사례
마감기한 (6월 7일 12시까지 해결한 문제)
팀프로젝트 하면서 경험했던 트러블슈팅과 해결 사례입니다.
기본 프로필 이미지 문제
문제점:
회원 가입 시 유저 테이블에 기본 이미지를 직접 저장하는 방식을 사용해서 불필요한 메모리 사용과 데이터의 일관성이 훼손되었습니다.
해결 방법:
- 기본 디폴트 이미지를 SUPABASE의 스토리지에 저장하고, NULL 값으로 유저 테이블에 프로필 사진을 변경했습니다.
- 회원 가입 시에는 기본 디폴트 이미지 링크만 참조하도록 변경했습니다.
- 마이 페이지에서 사용자 프로필 이미지 변경 기능을 추가했습니다.
결과: 데이터 일관성을 유지하면서 메모리 사용을 최적화했습니다.
팔로우 버튼 클릭 시 로그아웃 문제
문제점:
팔로우 버튼 클릭 시 로그아웃되는 문제가 발생했습니다. 이는 버튼이 form 태그 안에 있어서 새로고침이 발생하는 것이 원인이었습니다.
해결 방법:
- 문제를 일으키는 form 안의 버튼을 확인했습니다.
- event.preventDefault()를 추가하여 기본 폼 제출을 방지했습니다.
이 문제의 원인을 찾는데 시간이 오래 걸렸습니다. 이유는 새로고침 하면서 로그아웃이 되는 버그가 같이 발생해서 폼 제출이 되는 것과 미리 시험해본 팔로우 버튼은 페이지에서 잘 작동해서 버튼과 로그인 상태 관리에 인과관계가 있다고 생각했기 때문입니다.
결과: 팔로우 버튼을 누르면 로그아웃하지 않고 의도한 대로 토글되서 작동하게 되었습니다.
프로필 이미지 실시간 연동 문제
문제점:
마이 페이지에서 프로필 이미지를 변경해도 헤더에 실시간으로 반영되지 않는 문제가 있었습니다.
해결 방법:
- 기존에는 헤더에 프로필 이미지를 useState로 해당 컴포넌트에서 상태 관리를 했었습니다.
- 헤더 프로필 이미지를 전역 상태 관리를 위해 Redux로 상태 관리를 변경했습니다.
- 상태 변경 시 useEffect 의존성 배열에 Redux 상태를 추가하여 프로필 이미지가 실시간으로 업데이트되도록 했습니다.
결과: 프로필 이미지 변경 시 실시간으로 헤더에 반영되었습니다.
회원가입 후 바로 로그인하면 이전 로그인 기록으로 가는 문제
문제점:
회원가입 후 바로 로그인하면 이전 로그인 기록으로 이동하는 문제가 있었습니다. 이는 Supabase에서 새로 생성된 사용자 정보를 테이블에서 찾지 못하는 문제로 추정되었습니다.
해결 방법:
- Supabase에서 제공하는 회원가입 메서드는 자동으로 로그인 되는 기능이 있었습니다.
- Redux에서 유저의 로그인 상태 관리를 하면서 이전 로그인 토큰과 충돌이 났던 것 같았습니다.
- 로그아웃 상태일 시 이전에 비동기적으로 사용자 정보를 저장했던 부분을 제거했습니다.
- 회원가입 후 사이트에서 자동으로 로그아웃하고 로그인 페이지로 이동하도록 수정했습니다.
결과: 문제 해결 후 회원가입과 로그인 과정이 원활하게 진행되었습니다.
마감기한이후 조사하고 해결한 문제
새로고침 시 로그아웃 되는 문제
문제점:
사이트가 아직 완성되기 전 서버와 클라이언트 간에 비동기 작업처리를 확인 하기 위해 새로고침을 할 때 로그인 상태에서 로그아웃 되는 문제가 있었습니다.
알아보니 새로고침을 하면 메모리의 모든 상태가 리셋되어서 redux의 스토어의 상태도 초기 상태로 돌아가게 되고 현재 리둑스 auth의 초기 상태 설정값은 { user: null, status: 'idle', error: null }로 설정되었습니다. 따라서 새로고침 시 user가 null이 되어 로그아웃된 것처럼 보인 것입니다.
해결 방법:
- RTK에서 createAsyncThunk와 getSession() 메서드를 활용해서 User_API 폴더에서 getUser 메서드를 만들어서 현재 로그인 상태의 유저의 정보를 가져왔습니다.
- 최상단 위치에 있는 컴포넌트에서 useEffect로 마운트 될 때 1번에서 가공한 dispatch(getUser())로 데이터를 기록했습니다.
- getUser는 현재 사용자의 세션 정보를 가져오고 로컬 스토리지나 쿠키를 통해 정보를 가져와서 새로고침을 해도 이 정보는 유지됩니다.
- getUser가 호출되면, Supabase는 먼저 이 저장된 토큰을 찾습니다.
- 토큰이 유효하면(즉, 만료되지 않았다면), Supabase는 해당 토큰에 대응하는 사용자 정보를 반환합니다.
- 이 정보는 Redux 스토어의 auth.user에 저장됩니다.
- 실제로는 잠깐 로그아웃 상태가 되었다가 빠르게 다시 로그인되는 것이지만 체감 안되고 새로고침하면 로그인 상태로 유지한 걸로 보입니다.
결과: 문제 해결 후 회원가입과 로그인 과정이 원활하게 진행되었습니다.
페이지 이동 간에 데이터 로딩 시간이 너무 길었던 문제
문제점:
메인 페이지를 구현하면서 메인 페이지의 헤더 탭에 트렌딩, 최신, 팔로우, 마이 페이지 목록을 기준으로 정렬해서 아래에 gird 형식으로 데이터를 카드 리스트를 표시 했었는데 필요한 정보만 받기 위해 트렌딩, 최신은 전체 데이터를 받아오고 팔로우 버튼 클릭 시 DB에서 현재 팔로잉하고 있는 ID를 기준으로 데이터를 불러왔고 MyPage에 있는 카드 리스트는 현재 로그인한 ID를 기준으로 필요한 데이터를 받아오면서 페이지 네이션하면서 데이터를 불러왔었습니다.
해결 과정 및 결과:
- 이미지를 불러오는 로딩이 너무 길어서 useEffect와 useCallback등 메모제이션을 사용해서 메인 페이지의 불필요한 리렌더링을 최소화 해봤습니다. ex) PostItem와 페이지 이동하는 버튼에 React.memo()를 사용
- 문제를 해결하기 위해 조사해본 결과 LazyLoad가 처음 웹사이트에 접근할 때 리소스의 일부만 다운로드 되기 때문에 콘텐츠의 제공 속도가 빠르다는 장점을 보고 PostItem에 Image 부분에 적용해봤습니다.
- 페이지 초기 로딩을 하고 나서 페이지 간에 이동할 때 다시 데이터를 불러와서 로딩이 오래걸려 한번에 모든 데이터를 받아와서 최상위 App에 위치시켜서 redux로 상태 관리 useEffect에서 의존성 배열에 값이 변경 될 때만 변경하고 초기로딩엔 스켈레톤 로딩 적용해서 사용자가 페이지를 이용하면서 최대한 불편한 경험을 안 하게 하려고 노력했습니다. -> 하지만 의존성 배열이 변경되면 다시 오랜 로딩시간이 걸리는 문제는 안 고쳐짐
- 전체적으로 코드를 다시 보고 map같이 순회하는 메서드가 중첩된 부분이 존재하지 않고 최적화도 잘 구현 되었다고 생각해서 DB에 이미지를 보니 리스트의 이미지 파일들의 용량이 많이 커서 로딩 시간이 오래 걸렸던 것이였습니다.
결과: 문제 해결 후 페이지 로딩하면서 스켈레톤 로딩이 있는지도 모를 정도로 아주 빠른 속도로 로딩 되어졌습니다.
프로젝트를 하면서 스스로 잘했다고 생각한 점과 아쉬운 점 및 배운 점
잘한 점:
- Frontend:
- 리렌더링 최소화,
- 유효성 검사 처리(= 현재 사용자가 로그인 상태가 아닐 때 mypage 이동 등 디테일한 부분을 신경 썼습니다.)
- 조건부 렌더링 (= 로그인 상태 여부로 보여지는 헤더 내용, PostItem의 상세페이지에 사용자의 Id가 해당하는 아이템의 작성한Id을 확인해서 일치한다면 수정 가능하게 아니면 읽기 전용으로 렌더링, 댓글 기능 또한 수정 삭제 버튼 조건부 렌더링 했습니다)
- 유효성 검사 처리에서 예외 처리된 경우 토스트 팝업 라이브러리를 활용해서 사용자에게 정보를 전달 했습니다. 기존에 토스트 팝업 기능을 과제로 직접 구현해봐서 직접 구현하려고 했지만 기한이 얼마 남지 않아서 라이브러리를 사용해서 시간절약과 간단하고 기능이 좋은 토스트 팝업 기능을 활용해서 만족했습니다.
- Backend:
- Supabase에 유저 테이블과 게시글 테이블 등 테이블 간 관계를 외래키로 연결했습니다.
- 유저가 이름을 바꿨다면 작성자의 이름도 실시간으로 변경되고 게시글이 삭제되면 댓글도 삭제가 되도록 연결 시켰습니다.
- 데이터 베이스에서 받아오는 API를 클래스로 캡슐화해서 재사용성을 크게 높여서 팀원분들도 편하게 사용했습니다.
- State Management: Redux (Thunk)를 활용해서 비동기적으로 DB에서 데이터가 처리되고 다시 서버에서 클라이언트로 데이터를 전달하는 과정에서 나오는 시간의 간극을 Redux에서 전역 상태 관리로 모든 비동기 데이터 처리를 실시간 업데이트 되도록 구현 했습니다.
- 팀원과 협업: 최대한 빨리 맡은 역할의 기능을 구현하고 다른 분들과 협업하면서 위에 오류가 난 것을 같이 해결하려고 노력했고 그 결과 오류를 전부 해결 했었습니다.
아쉬운 점 및 배운 점:
- Supabase: Supabase를 처음 사용했으며, 데이터베이스와 클라이언트 간의 비동기 처리, 상태 관리 방법을 깊이 이해하게 되었던 과정이여서 기한이 일 주일이란 시간밖에 없어서 마감 시간 이후에 버그를 해결 했습니다.
- 데이터 최적화: 데이터베이스와의 연동에서 데이터 최적화의 중요성을 배웠습니다. 이미지의 용량이 커서 로딩이 오래 걸렸던 것이였지만 필요한 데이터만 불러오도록 비동기 처리와 메모이제이션을 통해 페이지 로딩 시간을 큰 용량임에도 불구하고 로딩시간이 계속 줄어드는 게 보였습니다.
조회수 기능: 제일 아쉬운 부분
왜 제일 아쉬운 부분이라고 생각했냐면 위의 오류들을 해결하느라 시간이 너무 부족했고 처음에 트렌딩 점수의 계산을 글 작성할 때 star와 조회수, 시간 등을 계산해서 정렬하려고 했습니다. 우선 메인 페이지를 구성하고 나서 헤더를 구성하고 다른 팀원분들한테 생긴 문제를 같이 해결하면서 후순위로 밀렸고 일단 초기에 supabase에서 정책을 수정해서 해당 항목인 views가 클릭시 항목이 +1 올라가게 구현 했습니다.
그 뒤로 누구나 조회수를 올릴 수 있게 하는 것은 좋은 방법이 아니라는 것을 알고 있었고 원래 생각했던 로직은 post_views 테이블을 만들어서 해당 항목에는 user_id, post_id, timestamp로 추가해서 현재 시간을 기록하고 해당 유저가 해당 게시물을 클릭한 시간을 조회해서 현재 시간과 timestamp에 저장된 시간을 비교해서 설정한 시간보다 클 경우(= 지난 경우) posts의 테이블의 조회수의 항목이 올라가는 것을 생각했었는데 보완하면 좋을 것 같습니다.
시간 관리와 학습 과정
시간 투자: 프로젝트 기간 (5월 31일 ~ 6월 7일)
프로젝트 기간동안 주말에 Supabase를 유튜브에 나온 강의를 들으면서 데이터베이스 관리와 비동기 처리에 집중하면서 학습을 했고 에러 해결에 시간을 많이 투자했습니다.
학습 방법:
- Supabase 공식 문서를 참고하며 Supabase의 기능을 이해했습니다.
- 문제 해결을 위해 다양한 시도를 했고, 코드 리뷰와 디버깅을 통해 문제를 분석하고 해결했습니다.
프로젝트 성과와 주요 개선점
성과:
- 데이터 최적화: 데이터 로딩과 처리 속도를 크게 개선하여 사용자 경험을 향상시켰습니다.
- 기능 완성도: 모든 주요 기능을 구현하고, 예상했던 성능 목표를 달성했습니다.
개선점:
- 코드 구조 개선: 일부 코드 구조와 컴포넌트 관리를 개선하여 유지 보수성을 높일 수 있습니다.
결론
이번 프로젝트를 통해 많은 것을 배웠고, 데이터베이스 최적화와 비동기 처리 등 유용한 기술들을 익힐 수 있었습니다. 앞으로도 지속적인 학습과 개선을 통해 더 나은 성과를 내고 싶습니다.
'TIL' 카테고리의 다른 글
TIL - TanStack Query의 주요 개념 (0) | 2024.06.11 |
---|---|
TIL - SPA 블로그 프로젝트 마무리 및 다음 계획 (0) | 2024.06.10 |
TIL- Supabase (1) | 2024.06.05 |
TIL (Today I Learned) - 팀 프로젝트를 하면서 오늘 배운 내용 (0) | 2024.06.04 |
TIL - 리액트 라우터 연결 방법: 문제와 해결 (0) | 2024.06.03 |