안녕하세요. 제가 코드스테이츠에서 약 4주기간 동안 진행하였던 Billy Zip 프로젝트에 대해서 블로깅을 해보려합니다.
프로젝트 소스코드는 아래의 Github repository에서 참고하실 수 있습니다.
Client : https://github.com/hsl0505/BillyZip_CLIENT.git
Server : https://github.com/hsl0505/BillyZip_SERVER.git
기획의도 및 프로젝트 소개
BillyZip이라는 프로젝트 이름은 '집을 빌린다'라는 의미에서 '빌리+집'을 영어로 바꾼 것입니다.
기존의 전월세, 보증금 등 부동산 매물마다 복잡한 계약이 있고, 기간 또한 대부분 1년 이상으로 짧은 기간동안 거주하는 것이 사실 어렵습니다.
빌리집 이름의 의미에서 알 수 있듯이, 빌리집은 자기가 살고 싶은 집을 예약 후에 일정 기간 동안 빌려서 살 수 있도록 해주는 새로운 개념의 구독형 주거 서비스를 제공하는 모바일 어플리케이션 프로젝트입니다.
빌리집을 통하여 유저들이 원하는 집에 짧게는 몇주부터 길게는 1년까지 원하는 기간동안 편하게 거주할 수 있는 서비스를 제공해보고 싶었습니다.
프로젝트 개요
프로젝트 기간 : 2020.01.31 ~ 2020.02.25 (약 4주)
서비스 종류 : Mobile Application
프로젝트 참여 인원 : Front-End 1명 / Full-Stack 2명
프로젝트는 약 4주동안 진행되었으며, 모바일 어플리케이션 (안드로이드 기준)으로 만들었습니다. 프로젝트는 팀프로젝트로 진행되었으며, 저 포함 총 3명의 팀원으로 진행하였습니다.
저는 빌리집 프로젝트에서 Front-End를 담당했습니다. Full-Stack을 담당한 다른 팀원 분들이 백엔드부터 프로젝트를 시작하였기 때문에 클라이언트 기본 구조 및 대부분의 기능을 제가 맡아 구현했습니다. 그럼 지금부터 제가 클라이언트에서 어떤 부분들을 구현했는지 소개해드리겠습니다.
Client 초기 설정 및 사용한 기술 스택
저희 프로젝트는 모바일 어플리케이션이기 때문에 React Native (EXPO) 사용하였고, React Hooks를 활용하여 모든 컴포넌트를 함수형 컴포넌트로 구성하였습니다.
또한 TypeScript를 도입하였고, ESLint와 Prettier를 활용하여 코드 스타일을 통일하였습니다.
ESLint의 경우 airbnb 스타일을 기본으로 설정하였고, typescript, airbnb hooks, react native 설정을 추가하여 사용하였습니다.
위에 열거한 기술들이 모두 작동할 수 있도록 expo cli (typescript)와 tsconfig, eslintrc, prettierrc 설정을 통하여 클라이언트 초기 세팅을 해주었습니다.
전체 스크린 네비게이션 설계 및 구현
React Navigation (4.x) 를 활용하여 전체 스크린을 구성하였습니다.
1. Bottom Tab Navigator
빌리집의 주요 스크린들 및 기능이 푸터를 통하여 구성되고 스크린 전환이 되기 때문에 bottom tab navigator로 전체적인 스크린 구조를 잡아주었고, 각 탭에 stack navigator로 필요한 스크린을 쌓아주어 빌리집의 전체적인 스크린을 구성하였습니다.
2. Switch Navigator
저희 프로젝트는 JWT를 활용하여 Authorization을 구현하였습니다.
그래서 JWT와 AsyncStorage를 이용하여 처음 앱 구동 시, AsyncStorage에 JWT 유무에 따라 로그인 및 회원가입 스크린 또는 홈 스크린으로 진입할 수 있도록 설계하였고, 이것을 switch navigator를 활용하여 구현하였습니다.
switch navigator를 활용한 또 다른 이유는, 유저가 로그인 한 후에 뒤로가기 등을 하였을 때, 다시 로그인 화면으로 돌아가는 것을 방지하기 위하여 switch navigator를 활용하였습니다.
여러가지 기능 구현
용량 관계로 시연영상을 링크로 첨부합니다 :)
전체 시연 영상 : https://www.youtube.com/watch?v=r7AFMYzc3Tc&t
각 기능 시연 영상 : https://www.youtube.com/channel/UCVdF-L1flv_52m2Q3c9pcyA/videos
(동영상 목록에 각 기능 별 영상을 참고해 주시면 감사합니다)
제가 클라이언트에서 구현한 기능은 다음과 같습니다.
- 로그인 / 로그아웃 / 회원가입 기능
- 홈 스크린 ( 추천 매물 / 매물 종류별) / 매물 종류별 전체 리스트
- 매물 등록 / 상세 열람 / 수정 / 삭제 기능
- 즐겨찾기 스크린 및 즐겨찾기 추가 / 삭제 기능
- 리뷰 스크린 및 리뷰 등록 / 삭제 기능
- 매물 관리 스크린 / 매물 구독 신청 수락 및 거절 기능
각 기능을 구현할때 고려하였던 부분을 아래에 설명하겠습니다.
로그인 스크린
처음 앱 구동 시 비로그인 상태의 경우 진입하는 로그인 스크린 입니다.
Animated view를 활용하여 로그인 스크린 진입 시에 컴포넌트들이 opacity transition이 되도록 하였습니다.
로그인 / 로그아웃 / 회원가입 기능
1. 로그인 기능
유저가 로그인 시, JWT를 서버로 부터 발급 받고 클라이언트는 AsyncStorage에 토큰을 저장합니다. 그리고 이 토큰을 활용하여 앱 구동 시 토큰이 만료 또는 유저가 로그아웃을 이전에 하지 않았으면 바로 홈 스크린으로 진입합니다. 또한 서버로 매 요청 시 AsyncStorage에 저장되어있는 토큰을 보내줌으로써 로그인 상태를 유지합니다.
또한 이메일이나 패스워드가 틀린 경우, 입력을 안한 경우 등 여러 경우에 따라 메시지가 나오도록 하였습니다.
2. 로그아웃 기능
유저가 로그아웃 시, 로그인 스크린으로 다시 전환됨과 동시에 AsyncStorage를 clear하여 로그인 시에 다시 JWT를 발급 받도록 구현하였습니다.
3. 회원가입 기능
회원가입 시에 생년월일을 입력하는 부분에서는 react-native-modal-datetime-picker 를 이용하여 연도와 날짜를 직접 선택할 수 있도록 하였습니다.
매물 종류별 리스트 스크린
매물의 갯수가 많을 때 Scrollview로 모든 매물을 한번에 렌더링 할 경우 성능이 떨어질 수 있기 때문에 FlatList를 활용하여 화면에 보여지는 매물만 렌더링이 되고, 스크롤을 내렸을 때 추가적으로 매물을 렌더링 할 수 있도록 하였습니다.
매물 등록 스크린
매물 등록에 필요한 이미지 및 위치 정보를 업로드하기 위해서는 모바일의 카메라/앨범 접근 권한과 위치 권한이 필요합니다.
그래서 EXPO의 Image-picker, Location, Permission으로 비동기 처리 로직을 구현하여 매물 등록 스크린 진입 시에 권한 접근에 대한 허용을 받도록 하였습니다.
Image-picker를 활용하여 이미지 업로드 시 앨범에 있는 이미지 또는 카메라로 사진을 찍어서 바로 업로드 할 수 있도록 하였습니다.
매물에 대한 이미지는 여러장일 수 있기 때문에 react-native-snap-carousel이란 라이브러리를 활용하여 Carousel과 Pagination으로 이미지를 넘겨볼 수 있도록 구현하였습니다.
또한 업로드한 이미지 중에 대표로 보여질 이미지를 설정할 수 있도록 하였습니다.
업로드 이후에는 자신이 작성한 매물의 상세 열람 스크린으로 navigation되도록 하여 자신이 작성한 매물을 확인할 수 있도록 하였습니다.
매물 상세 열람 스크린
매물 등록 스크린과 마찬가지로 Carousel, Pagination을 이용하여 이미지를 넘겨볼 수 있도록 구현하였고, 이미지 오른쪽 상단에 즐겨찾기 버튼을 눌러 자신의 즐겨찾기 목록에 추가 될 수 있도록 하였습니다.
특정 스크린 진입 시 Component와 Navigation Life Cycle
웹에서는 한 화면(컴포넌트)에서 다른 화면으로 전환될 때 기존의 컴포넌트가 unmount되고 난 후에 다른 컴포넌트가 mount됩니다.
하지만 앱(React navigation)의 Stack navigator에서는 기존의 스크린에서 다른 스크린으로 넘어갈 경우, 기존의 스크린이 unmount되지않고 그 위에 stack이라는 이름처럼 또 다른 스크린이 쌓입니다.
이러한 Stack navigator의 특징 때문에 이슈가 한가지 있었습니다.
기존의 스크린에서 componentDidMount 동작을 통하여 서버로부터 데이터를 받아와 렌더링하고, 다른 스크린으로 넘어간 후 어떠한 기능 동작을 하고 다시 기존 스크린으로 오면 기존 스크린이 unmount 되지 않았기 때문에 서버로부터 최신 데이터를 받아와 렌더링을 하지 않고 기존의 데이터를 계속 렌더링하였습니다.
그래서 이 문제를 React navigation의 Life cycle인 didFocus기능을 활용하여, 스크린이 focuse될 때마다 컴포넌트의 unmount여부와 상관없이 최신 데이터를 서버로 부터 받아오도록 구현하였습니다. React Hooks를 활용하여 함수형 컴포넌트로 만들었기 때문에 useEffect hook과 didFocus를 같이 사용하여 구현하였습니다.
비동기 처리 및 helper 함수 모듈화
AsyncStorage 비동기 함수 및 권한 접근 허용 비동기 함수 등 여러 비동기 함수 및 helper 함수를 모듈화하여 사용하였습니다.
특히, Axios를 instance화하여 사용하였는데 Axios 요청을 서버에 보낼 경우 유저의 인증 상태를 유지하기 위해서 클라이언트에서 가지고 있는 JWT를 보내줘야했습니다.
Axios 코드를 작성할 때마다 AsyncStorage에서 JWT를 꺼내와서 보내주는 코드를 같이 작성하는 것은 비효율적이기 때문에 Axios instance에 interceptor를 구현하여 매 요청마다 JWT를 자동으로 보내줄수 있도록 하여, 코드를 반복적으로 작성하지 않도록 하였습니다.
전반적인 UI 및 디자인 구현
- 리액트 네이티브 컴포넌트 라이브러리 중 React Native Elements를 커스터마이징하여 전반적인 UI를 구현하였습니다.
- Card나 List 등 컴포넌트를 재사용하여 각 스크린에 맞게 렌더링 되도록 하였습니다.
- 사용된 icon은 expo에 내장되어있는 expo-vector-icon을 사용하였습니다.
- 디자인의 경우 비슷한 에어비앤비를 많이 참고하였고, 컴포넌트를 구현하면서 그때그때 각 컴포넌트에 맞게 디자인을 구현하였습니다.
회고
4주라는 시간이 정말 빠르게 지나갔습니다.
프로젝트에 사용하였던 기술 스택이 전부 새로 사용하는 기술이라서 프로젝트를 처음 시작할 때 내가 저 기술들을 잘 활용할 수 있을까 하는 걱정이 있었습니다.
프로젝트를 진행하면서 새로운 기술에 대해 필요한 개념을 빠르게 익히고, 좋은 레퍼런스를 찾아 참고하고 코드를 작성하면서 있었던 이슈를 해결하기 위해 많이 노력했던 것 같습니다.
이러한 과정을 통하여 새로운 것을 익히고 적용할 수 있는 저만의 학습엔진이 생겼다고 생각합니다.
또한 경험해보고 싶었던 기술들을 사용할수 있어서 좋았습니다.
평소에 TypeScript와 React Hooks를 경험해보고 싶었는데 이번 프로젝트를 통해 저 기술을 사용해봄으로써 저 두 기술이 왜 핫하고 어떤 장점이 있는지 알 수 있어서 좋았습니다.
아쉬운 점도 많이 있었는데 우선 상태관리 라이브러리를 도입하지 못한 점이 아쉬웠습니다. 프로젝트를 많이 해보진 않았지만, 리액트 프로젝트를 하면서 항상 상태관리에 대한 라이브러리를 사용해보고 싶었는데 이번에도 프로젝트 기간과 다른 새로운 기술 스택에 대한 러닝커브로 인하여 도입하지 못한게 아쉽습니다.
또한 조금 더 노력했으면 좀 더 좋은 퀄리티의 프로젝트가 나오지 않았을까 하는 아쉬움도 있습니다.
다음 프로젝트를 시작한다면 이번 프로젝트의 경험을 토대로 좀 더 퀄리티 있고 좋은 코드를 작성할 수 있을 것 같습니다.
이상 프로젝트 블로깅을 마칩니다. 봐주셔서 감사합니다 :)
'Project Portfolio' 카테고리의 다른 글
SO Bucket 프로젝트 (0) | 2020.03.12 |
---|
댓글