리액트 웹앱 이웃의마켓 중간 점검

· #과업 #react

8월 초부터 시작한 이웃의마켓 프로젝트를 중간 발표하였다. 리액트 웹앱을 개발하면서 느낀점을 써보려한다.

개발 초기

이웃의마켓은 지역주민들이 같이 물품을 구매하거나 공유할 수 있도록 해주는 커뮤니티 사이트다. 사용 예시로, OTT 공동 구매, 배달비 공동 부담, 유통기한이 임박한 식품 공유 등이 있다. 당근마켓과 유사하지만 당근마켓은 중고물품 판매, 구매에 초점이 맞춰져 있고, 이웃의마켓은 공동구매, 물건공유에 초점이 있는 것이 다르다.


리액트를 여러번 써봤지만 직접 기획, 디자인된 서비스를 개발해 본 것은 처음이었다. SPA를 기반으로 실시간 서비스를 지원하는 플랫폼이기 때문에 react CRA를 사용했다. 초기 환경은 airbnb eslint, prettier, global styled component, git convention, css convention, 폴더 구조, npm를 설정했다. 혼자 프론트엔드개발을 맡았지만 git convention, PR을 통해 통일감을 주고, 유지보수가 편하게 했다. airbnb eslint를 통해 js, react 코드에 대한 규칙들을 되돌아보았다. eslint의 세세한 설정들은 예외처리를 했다.

개발 과정

중간발표까지 3주 간 개발을 했다. 주요 개발은 소셜로그인, 회원가입, 동네등록, 게시판 등록, 상세, 목록을 진행했다. 소셜로그인은 kakao, naver를 이용했다. 백엔드에서 모두 처리를 했기 때문에 프론트에서는 백엔드 url만 링크를 하면 백엔드에서 소셜로그인을 모두 처리하고 프론트 callback url로 jwt토큰을 넘겨주는 형식으로 진행되었다. jwt토큰을 localstorage에 저장하고, swr를 이용해 서버에 유저정보를 요청할때마다 이용했다.


회원가입은 소셜로그인 후 추가정보를 받기 위해 진행된다. 닉네임, 전화번호, 이메일을 추가로 사용자에게 요청을 한다. onKeyUp 이벤트를 이용해 사용자가 키보드를 누르고 땔때마다 실시간으로 validation 체크를 할 수 있도록 하였다. 닉네임 중복체크는 onBlur를 이용해 Input창에 포커스가 해제되었을때만 검사했다. onKeyUp으로 검사하면 UX는 더 좋아지지만 한 글자입력할때 마다 서버에 API를 요청해야 하므로 네트워크 요청이 많아지는 문제가 있기 때문이다. 닉네임, 전화번호, 이메일의 validation이 모두 완료되었을때 폼을 제출할 수 있도록 하였다.


동네등록은 사용자가 현재 동네를 등록하는 기능이다. 회원가입 후 추가적으로 원하는 동네를 선택할 수 있다. 현재는 마포구의 몇몇 동만 하드코딩해서 넣어두었다. 최대 3개까지를 선택 할 수 있고, 동네마다 다른 게시글들을 볼 수 있도록 했다. 기능 구현을 위해 최상위 컴포넌트에 현재 동네, 모든 동네를 useState를 통해 상태로 선언했다. 그리고 동네설정 컴포넌트에 prop으로 넘겨주어 처리했다.


게시판 목록, 상세, 등록 기능을 개발하는 것이 제일 어려웠다. 리액트에서 CRUD는 접해봤지만 응용해서 적용하려고 하니 다시 공부를 해야했다. 일단 전체적인 데이터부터 상태관리를 하는데 전역상태관리 툴을 쓰지 않아 개발하면서 점점 번거로운 점이 생겨났다. 또한 데이터 정렬 로직을 제대로 신경쓰지 않아 불필요한 렌더링이 일어났다. 이는 추후 개선해야할 점들이다. 게시판 등록 기능에선 비즈니스 로직을 세세하게 신경쓰다보니 코드가 점점 난잡해져갔다. 이를 시각화하거나 구체화하지 않는다면 나중에 리팩토링하기 힘들 것 같다. 사진파일 등록 및 게시는 input type='file'과 web API인 URL.createObjectURL를 이용했다.


등록 기능에서 15개정도의 상태를 관리해야했다. 현재는 컴포넌트 간 deps가 깊지 않기 때문에 괜찮지만 프로젝트가 커질때를 대비해서 전역상태 관리 툴을 도입하는 것이 좋아보였다. 하지만 그렇게 많은 상태를 관리하는 것은 아니니 기본적으로 리액트에서 제공하는 Context API를 이용해야겠다고 생각했다. 게시판 데이터, 동네 데이터, 검색, 정렬도 서버에서 API로 불러오게 된다면 swr를 통해 실시간으로 불러올 것이므로 더더욱 프론트에서의 상태관리 폭은 줄어들 것이다.

배포

처음에는 github-page를 이용해 배포하였다. 하지만 github-page는 기본적으로 github-organiztion/repository의 url구조를 가지고 있어 프론트 라우팅 설정하는데 불편할 뿐더러 도메인이 거슬렸다. 또한 .env파일에 저장되는 backend url같은 global 변수들도 github에 그대로 노출시켜야 되는 단점이 있었다. github-action을 사용하지 않는다면 CI/CD도 자동으로 되지 않는 점도 있었다. netlify를 통해 이를 모두 해결했다. domain을 custom설정해서 neighbors-market.netlify.app으로 더 깔끔하고 직관적으로 바꿀 수 있었다. netlify에서 global 변수를 추가하여 .env파일을 github에서 숨길 수 있었다. 또 github 특정 branch를 선택하면 PR, push에 있어서 자동으로 CI/CD를 해주므로 github-action에 익숙하지 않는 나에겐 매번 build, deploy할 필요가 없어서 좋았다.

아쉬운점 및 개선점

가장 아쉬운점은 성능최적화를 신경쓰지 못했던 점이다. 3주간 최대한 기능을 개발하기 위해 component분리 및 css convention을 지키지 못한 점도 아쉽지만, 무엇보다 useCallback, useMemo등을 이용해 각 input들을 독립적으로 만들지 못했다. 게시판 등록에서는 하나의 input이 변경될때마다 10개 정도의 input이 모두 리렌더링되었다. text input에서 심지어 한글자 칠때마다 약 0.3초간 지연 입력되는 현상이 나타나기도 하였다. 프로젝트가 커져나가고, 실제로 서비스에 앞서 가장 먼저 신경써야 할 부분이라고 생각한다. 앞으로 2주간 먼저 컴포넌트들을 분리하고 렌더링을 최적화하는데 초점을 맞춰 리팩토링을 진행할 생각이다. 기본적으로 리액트에서 제공되는 hook들을 적용해보고, 성능과 보안이 더 좋다는 react-form이라던가 하위 컴포넌트만 리렌더링 해주는 전역상태관리 툴의 도입도 생각해보려한다.


앞으로 2주간은 리팩토링 및 기능 보완을 할 예정이다. 그 이후 9월 말까지 web socket을 이용해 채팅기능을 구현해 실사용자 테스트를 진행하려고 한다. 주된 목표는 성능을 최적화하는 것이다. 이외에도 컴포넌트 분리, style convention, react-DnD를 활용한 사진파일 drag n drop, axios를 이용한 토큰 재발급 기능, swr에서 react-query로의 변경등을 목표로 하고 있다. 추가로, 페이지 로딩시에 사진파일이 늦게 불러와져서 UX를 해친다고 생각한다. 유튜브처럼 페이지가 변경될때 잠깐 원모양의 로딩창이 뜬 후 모든 페이지를 보여준다던지, 스켈레톤 UI를 도입하는 것도 욕심이 난다.

JIRA 도입

그 밖에도 이번에 jira를 처음 프로젝트에 도입해봤다. 중간 발표까지 시간이 많이 부족해 애자일 형식으로 스크럼방식을 사용해 1주 스프린트 적용해 개발했다. jira를 software개발 기본 템플릿을 사용하니 생각보니 간단하고 협업에 도움이 많이 되었다. 스스로도 어떤 기능을 구현해야하는지, 얼마나 진행되고 있는지를 jira를 통해 관리할 수 있다는 점이 좋았다. 협업에 있어서는 팀원 간 서로 어떤 일을 하고 있고, 얼마나 진행되었는지를 알 수 있어서 좋았다.


스스로 가장 크게 와닿은 점은 1주 스프린트 방식 개발이었다. 프론트는 1인개발이라 결국 혼자 하긴 했지만 1주간의 스프린트 계획을 하고 피드백을 하면서 스스로의 능력을 더 이끌어 낼 수 있었다. 스프린트 방식을 쓰기전보다 확실히 스트레스는 더 많이 받았지만 좀 더 업무에 집중할 수 있었다. 결과물도 더 좋았다. 앞으로도 스프린트 방식을 통해 개발하려고 한다. jira를 좀 더 써보며 협업에 있어서도 여러부분들을 개선해 나가려한다.