Home
home

💻 개발위키

“개발 이야기”에서 더 많은 개발 기록들이 담겨있습니다.  yoon-ho.com/portfolio/projects/wafflecard/story

목차

 리팩토링 진행중입니다. (2022년 2월 1일 ~ 진행중)

 waffle-card.web.app (FE) v1.0.0 - 이전 버전
 wafflecard.netlify.app (FE) v2.0.0 - 리팩토링 진행중
 이슈
API서버는 코발트의 이선협님이 제공해주신 서버를 활용하여 개발을 진행했습니다.
해당 API서버를 모든 팀에서 공통으로 사용하다보니 응답 데이터의 형태의 복잡성 비효율적인 네트워크요청의 문제가 있습니다. 이를 해결하기 위해 NodeJS, Express를 활용하여 API 서버를 개발하려고 합니다.
API 서버 구현 완료하였습니다.  https://waffle-card.herokuapp.com

 앱의 구조

컴포넌트 구조
페이지, 컴포넌트, 전역상태, 커스텀훅의 구조를 파악하기 편하도록 다이어그램을 작성했습니다.

개발 시나리오

1.
피그마를 참고하여 재사용되는 컴포넌트와 재사용되지 않는 컴포넌트를 분리하였습니다.
2.
이후 아토믹 디자인 패턴을 활용하여 bottom-up 방식으로 개발을 진행하였습니다.
3.
atommoleculeorganismpage
4.
스토리북을 활용하여 컴포넌트 뷰 테스트를 진행하고 및 문서화를 하였습니다.
5.
성능개선, 버그제거, 부족한 기능 추가를 진행하며 리팩토링을 진행하고 있습니다.

사용한 기술 스택

Javascript, Typescript, React
Context, Recoil, Axios
Storybook, Emotion, Mui
ESLint, Prettier, Netlify

전역 상태 관리

user - (recoil)
유저의 아이디, 이메일, 이름을 저장합니다.
단순하게 상태를 저장하기 때문에 recoil을 활용하였습니다.
waffleCards - (context)
와플카드 목록 데이터는 홈페이지의 탭에 따라 아래와 같이 3가지로 분류됩니다.
total : 전체 와플카드 목록
my : 나의 와플카드 목록
like : 좋아요한 와플카드 목록
3가지 항목을 캐싱하여 불필요한 네크워크 요청을 줄였습니다.
ModalProvider - (context)
서비스 특성상 렌더링할 모달 컴포넌트의 갯수가 많습니다. 이를 효율적으로 관리하기 위해 렌더링할 모달 컴포넌트 리스트를 관리하는 전역 상태입니다.
렌더링할 컴포넌트를 상태로써 관리하고 렌더링할 모달 컴포넌트에 prop을 함께 넘겨줄 수 있도록 설계하였습니다.
LoadingProvider - (context)
시간이 소요되는 로직에서 로딩 스피너를 활성시키는 상태값과 상태값을 변경하는 Dispatch함수를 제공합니다.
Spinner 컴포넌트를 자식으로 가지며 이를 위해 context 를 활용하였습니다.

API 요청

axios인스터스를 활용하여 baseURLtimeout을 설정하였습니다. 또한 인터셉터를 활용하여 요청과 응답을 가로채어 데이터의 형태를 사용하기 편하도록 구조분해하여 반환하도록 처리하였습니다.
와플카드 api 명세서

userApi

signUp : 유저의 정보로 회원가입을 요청합니다.
login : 로그인 정보로 로그인을 요청하고 jwt 토큰을 응답으로 받습니다.
me : jwt 토큰의 유효성을 검사합니다.
updateUser : 유저의 닉네임, 비밀번호를 변경합니다.

waffleCardApi

getWaffleCards : 와플카드의 전체 목록을 받아옵니다.
getWaffleCardById : 특정 id의 와플카드를 받아옵니다.
getMyWaffleCard : 나의 와플카드를 받아옵니다.
getMyLikedWaffleCards : 좋아요한 와플카드 목록을 받아옵니다.
createWaffleCard : 와플카드를 생성합니다.
updateWaffleCard : 와플카드를 수정합니다.
deleteWaffleCard : 와플카드를 삭제합니다.

commentApi

getCommentsByWaffleCardId : 특정 id의 와플카드에 속한 댓글을 받아옵니다.
getCommentById : 특정 id의 댓글을 받아옵니다.
createComment : 댓글을 생성합니다.
updateComment : 댓글을 수정합니다.
deleteComment : 댓글을 삭제합니다.

likeApi

createLike : 좋아요를 생성합니다.
deleteLike : 좋아요를 삭제합니다.

컴포넌트

아토믹 디자인 패턴을 활용하여 재사용성을 높이고 의미적으로 컴포넌트를 분리하여 개발하였습니다.
아토믹 디자인 패턴
atom : 하나의 기능 - 더 이상 나눠지지 않는 최소 요소 (재사용 가능)
molecule : 하나의 역할 - 데이터를 표시하고 이벤트를 받을 수 있지만 하나의 역할만 가능 (재사용 가능)
organism : 하나의 요구사항 - 사용자에게 의미를 가지는 기능적 요구사항에 포함되는 경우 (재사용 불가)

Atom

하나의 기능 - 더 이상 나눠지지 않는 최소 요소 (재사용 가능)
Button
앱에서 사용되는 버튼 컴포넌트입니다.
Input
이름, 휴대폰 번호, 주민등록 번호 입력 필드에 사용되는 컴포넌트입니다.
Portal
자식요소를 body태그 최상단으로 이동시키는 컴포넌트입니다. 로딩을 표시하는 Spinner 컴포넌트에서 활용하였습니다.
Text
앱에서 사용되는 텍스트 컴포넌트입니다.

Molecule

하나의 역할 - 데이터를 표시하고 이벤트를 받을 수 있지만 “하나의 역할”만 가능 (재사용 가능)
ColorPicker
와플카드를 생성하거나 수정할 때 컬러를 지정하기 위한 컬러 팔레트 피커입니다.
EditBox
자신의 와플카드나 댓글에 마우스를 호버하였을 경우 나타나는 콤보박스이며 수정, 삭제 기능을 제공합니다.
LikeToggle
와플카드를 좋아요 기능을 나타내는 컴포넌트입니다.
LoginGuide
로그인 안내 가이드를 나타내는 컴포넌트입니다.
Modal
Portal 컴포넌트를 활용하여 body태그 최상단에 렌더링되며 컨텐츠를 전달받아 표시하는 모달 컴포넌트입니다.
NoCardGuide
카드가 존재하지 않다는 아내를 나타내는 컴포넌트입니다.
ScrollGuide
홈페이지의 카드 목록을 가로스크롤로 활용하는 것을 안내하는 컴포넌트입니다.
Spinner
시간이 소요되는 비동기 로직에서 로딩상태를 UI로 표시되는 컴포넌트입니다.
Tab
홈페이지에서 와플카드의 목록을 필터링하는 탭 컴포넌트입니다.
total, my, like 3가지 탭 종류가 존재합니다.

Organism

하나의 요구사항 - 사용자에게 의미를 가지는 기능적 요구사항에 포함되는 경우에 해당되는 컴포넌트 (재사용 불가)
CardEditModal
자신의 와플카드를 생성하거나 수정하는 기능을 나타내는 컴포넌트입니다.
ChattingCardModal
와플카드를 클릭하면 나타나는 채팅 컴포넌트입니다.
Header
앱의 헤더를 나타내는 컴포넌트입니다.
Modals
렌더링할 모달들을 한번에 관리하는 용도의 컴포넌트입니다.
NameEditModal
유저의 이름(닉네임)을 수정하기 위한 모달 컴포넌트입니다.
PasswordEditModal
유저의 비밀번호를 수정하기 위한 모달 컴포넌트입니다.
WaffleCard
홈페이제이서 렌더링되는 와플카드를 나타내는 컴포넌트입니다.
WaffleCardList
와플카드들을 담고 있는 컨테이너 컴포넌트입니다.
waffleCards 전역 상태에 의존하여 type에 따라 다른 와플카드 목록을 렌더링합니다.

페이지별 로직

HomePage(홈페이지)

탭에 따라 와플카드 목록을 렌더링합니다.
로그인이 되어 있지 않다면 "오늘의 카드"(total) 목록만 렌더링이 됩니다.

SignUpPage(회원가입 페이지)

회원가입을 진행합니다.
각 Input에 따라 폼 검사를 진행합니다.

LoginPage(로그인 페이지)

로그인을 진행합니다.
각 Input에 따라 폼 검사를 진행합니다.

MyPage(마이 페이지)

유저의 이메일, 이름(닉네임) 정보를 확인하고 로그아웃할 수 있으며 닉네임과 비밀번호를 변경합니다.
닉네임과 비밀번호를 변경은 모달로 진행되며 폼 검사를 진행합니다.

커스텀 훅

컴포넌트에서 자주사용되는 로직을 재사용하거나 로직을 분리하기 위해 커스텀 훅으로 분리하여 개발을 진행했습니다.

useClickAway

지정한 컴포넌트의 외부를 클릭했을 때 콜백함수를 실행시켜주는 훅입니다.
리턴값으로 ref 를 반환하며 인자로 콜백함수를 정의합니다.
ref로 지정한 컴포넌트 외부를 클릭하면 콜백함수가 실행됩니다.

useForm

폼 검사, 폼이 제출되었을 때 콜백함수 실행 등 폼에 대한 처리를 하는 훅입니다.
인자로 초기값(initialValues), 제출될 때 실행되는 콜백함수(onSubmit), 폼의 유효성을 검사 함수(validate) 를 지정합니다.
반환은 아래와 같습니다.
handleChange : 값이 바뀔때마다 폼의 입력 값을 저장하고 타이핑중인 상태(isTyping)를 true로 변경합니다.
handleSubmit : 폼이 제출되었을 때 실행되는 로직으로 여태까지 저장되어 있는 폼 데이터들을 검사하고 인자로 넘겨받은 콜백함수(onSubmit)에 값을 넘겨 실행시킵니다.
isLoading : 폼이 제출되었을 때 시간이 소요되는 비동기 로직 실행되는 것을 고려하 제출 로딩중인 아닌지 boolean 값을 제공합니다.

useHover

지정한 컴포넌트에 마우스가 호버되었는지의 상태를 활용하기 위한 훅입니다.
리턴값으로 마우스가 호버되었는지의 상태를 나타내는 stateref를 반환합니다.
반환받은 ref를 컴포넌트에 지정하게 되면 해당 컴포넌트에 마우스가 호버되었을 때 반환받은 상태값이 true로 변경됩니다.

useIsOverflow

지정한 컴포넌트의 컨테츠가 오버플로우되었는지 상태를 활용하기 위한 훅입니다.
리턴값으로 컴포넌트의 컨텐츠가 오버플로우되었는지 상태를 나타내는 isOverflowref를 반환합니다.
반환받은 ref를 컴포넌트에 지정하게 되면 해당 컴포넌트의 컨텐츠가 오버플로우되었을때 반환받은 상태값이 true로 변경됩니다.

useModals

렌더링할 모달 컴포넌트들을 한번에 관리하기 위한 훅입니다.
리턴값으로 렌더링 시킬 모달 컴포넌트를 렌더링하기 위한 openModal 함수와 모달 컴포넌트를 닫기 위한 closeModal 함수를 반환합니다.
openModal 함수의 인자로는 렌더링시킬 컴포넌트와 prop을 전달합니다.
closeModal 함수의 인자로는 렌더링을 종료할 컴포넌트를 전달합니다.

useScrollToBottom

지정한 컴포넌트의 스크롤을 최하단으로 내리는 훅입니다.
리턴값으로 ref 를 반환하며 인자로 deps를 지정할 수 있습니다.
반환받은 ref를 컴포넌트에 지정하게 되면 해당 컴포넌트의 스크롤을 최하단으로 내리게됩니다.

useSessionStorage

키와 초기값을 활용하여 세션스토리지를 안전하고 편하게 사용하기 위한 훅입니다.
인자로 세션스토리지의 키(key) 와 값이 없을때의 초기값(initialValue)을 전달합니다.
반환값은 세션스토리지의 해당하는 키의 밸류인 storedValue 와 해당 세션스토리지의 키에 값을 저장하는 setValue 함수를 반환합니다.

useToggle

토글 상태를 편하게 관리하기 위한 훅입니다.
인자로 토글의 초기값(true or false)인 initState 를 전달합니다.
반환값으로 토글상태를 나타내는 state 와 상태를 토글하는 toggle 함수를 반환합니다.

useUser

유저의 전역 상태를 활용하여 로그인, 로그아웃, 유저정보 변경에 대한 처리를 하는 훅입니다.
user 전역 상태에 의존합니다.
반환값은 아래와 같습니다.
login : 유저의 이메일, 비밀번호를 받아 로그인 api요청을 보내고 응답으로 받은 jwt토큰을 세션스토리지에 저장합니다.
logout : 세션스토리지의 jwt토큰을 삭제하고 user 전역 상태를 삭제함으로써 로그아웃을 진행합니다.
updateUser : 유저의 닉네임(이름) 혹은 비밀번호를 전달받아 "유저 정보 변경" api 요청을 보내고 유저정보를 업데이트 합니다.