프론트엔드 개발 포트폴리오 | 혼합주 레시피 공유 사이트
내일배움캠프 4기 웹 개발 과정 React 트랙 수료생 최종 프로젝트 ‘OHZU’을 소개합니다.
Aug 16, 2023
오늘의 혼합주 OHZU
본인의 취향에 관심이 많고 혼합주를 선호하는 2030 세대를 위한
자신만의 혼합주 레시피와 비율을 공유하는 커뮤니티 입니다.
✅ OHZU 프론트엔드 목표
직관적인 UX/UI 구성
- 페이지에 들어왔을 때, 5~10초 안에 어떤 컨셉의 서비스인지 유저가 인지할 수 있도록 할 것
- 어떤 버튼을 누르거나, 액션을 취할 때 유저가 예상하는 것들을 보여지도록 할 것
- 모바일 환경에서도 위와 같은 목표를 이루도록 할 것
✨ OHZU 아키텍처 구성
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F58bfffcc-d538-42cb-b9d8-5beabcb140f4%252FFrame.png%3Ftable%3Dblock%26id%3Dedda8a00-0680-4a8d-8485-265c5410e718%26cache%3Dv2&w=3840&q=75)
📁 OHZU 사용 스택 및 기술적 의사 결정
1️⃣ Library & Language
React
- 새로고침을 하지 않으며, 사용자 인터렉션에 따라 필요한 부분만 리렌더링이 되도록 하기 위해 사용합니다.
- 컴포넌트 단위의 개발이 가능하여 생산성과 유지보수가 용이하여 사용합니다.
Redux Thunk vs. React-Query (서버 상태 관리)
- React Query
- Redux를 사용하기 위한 보일러플레이트 코드가 많습니다. 반면 React Query를 사용하면 Redux보다 프로젝트 구조가 단순해져 애플리케이션을 유지 보수하기 쉽고, 새로운 기능을 쉽게 구축할 수 있습니다.
- Redux는 API 상태를 관리하기 위한 규격화된 방식이 없습니다. 전역 상태 관리 라이브러리이기 때문입니다. 반면 React Query는 서버 상태를 관리하는 라이브러리입니다. Hook을 사용하여 React Component 내부에서 자연스럽게 비동기 서버 데이터를 사용할 수 있는 방법을 알려줍니다.
JavaScript vs TypeScript
- TypeScript
- JavaScript(이하 JS)는 개발환경에서 에러를 감지하기 어렵습니다(런타임 에러). 반면 TS는 개발중에 조기 버그를 감지할 수 있습니다(컴파일 에러). 따라서 버그 및 예상치 못한 동작 가능성을 줄일 수 있습니다.
- 버그 및 에러를 빨리 캐치할 수 있습니다. 이는 곧 서비스 유지 관리가 수월합니다.
2️⃣ Next.Js
- 검색시 CSR의 단점인 SEO(검색엔진 최적화) 기능을 보완할 수 있습니다.
- SSR 방식을 사용하여 사용자가 초기화면을 볼 때 로딩없이 HTML을 볼 수 있고, JS 다운로드 후 페이지 이동시 CSR 방식으로 브라우저에서 처리하게 하므로 보기 편합니다.
- 직관적인 페이지 기반 라우팅 (/pages/search/cocktail) 기능이 있습니다. 페이지 기반 라우팅 시스템을 채택하는 Next.js는 React보다 페이지 이동을 구현하는 데 있어서 수월합니다. (Client-Side-Navigatin)
- React는 CSR방식이라 검색엔진 최적화에 매우 불리합니다. 반면 Next.js는 검색엔진 최적화에 적합한 SSR 기능과 CSR을 구현하여 React의 단점을 커버합니다.
3️⃣ Axios
- Fetch를 사용하여 데이터를 요청시 Response객체를 담고있는 Promise를 반환합니다.
- fetch로 데이터를 사용하기 위해서는 JSON.stringify()를 사용해야합니다. Promise 객체를 문자열로 변환한 뒤, 데이터를 사용할 수 있습니다.
- 반면, Axios는 즉시 사용할 수 있는 JSON객체를 담고 있는 Promise를 반환합니다.
⇒ 카카오 회원가입/로그인 시, 유저 정보를 JSON으로 즉시 사용하기 위해서 Axios를 선택했습니다.
4️⃣ Tailwindcss
- 서비스 특성상 모바일 유저가 많을 것으로 예상하여, 모바일 반응형 스타일링에 유용한 tailwind를 선택했습니다.
- 클래스 작명에 많은 시간을 소요하지 않고, 유지보수가 편리하여 채택했습니다.
- 일관성 있는 디자인 시스템을 적용할 수 있고, JIT compiler로 인해 제한적이지 않아서 협업에 있어서 편리한 부분들이 많아 채택했습니다.
5️⃣ Firebase
- 직접 Server를 구축하지 않고 손쉽게 데이터를 저장 및 조작할 수 있기 때문에, 백엔드 파트에 소요되는 시간을 줄여 UI/UX 향상에 더 많은 시간을 투자할 수 있으므로 채택하였습니다.
6️⃣ Vercel
- Git이 연동되어 배포 과정이 단순하고 쉬우며 과정을 확인할 수 있어서 채택했습니다.
- CDN서버가 우리나라에도 있어 TTFB가 빠른편이어서 채택했습니다.
🚀 트러블 슈팅
Firebase Method로 검색 기능 구현
문제
저희팀은 부분 검색(Full-text search) 기능을 원했습니다.
하지만 Firebase method로는 정확한 키워드를 입력해야 검색(Exact-text search)이 되었습니다.
ex) “블루레몬에이드” ⇒ “블루레몬에이드” ( O ) / “블루레몬” ⇒ “블루레몬에이드” ( X )
실제로 Firebase Doc에서 자료를 찾아보면, 검색 라이브러리로 Algoria(유료) 등의 라이브러리를 사용하는 것을 권장하고 있습니다.
해결방안
fuse.js 공식 사이트에 들어가서 method를 다 찾아보았습니다.
하나씩 적용해보면서 “threshold, distance” method에서 힌트를 얻었습니다.
- threshould : 단어 검색 시, 엄격함을 조절합니다. (엄격 0.0 ~ 1.0)
- distance : 검색 결과의 유사도를 결정하는 가중치를 입력합니다. (엄격 0 ~ 1000)
⇒ 두 가지 method를 사용하여 검색의 엄격함을 Setting했습니다.
그 결과, fuse.js를 사용하여 저희 팀이 원하는 단어 검색 기능을 구현해냈습니다.
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fc8c48512-7208-44ba-9793-ca4b7b46ce09%252Fcarbon.png%3Ftable%3Dblock%26id%3D4907156a-8a0d-48f3-86a6-860849096203%26cache%3Dv2&w=3840&q=75)
게시물 작성중 페이지 이동 방지
문제
- 게시물 작성중 페이지 이탈시 작성중인 데이터 소실
- 새로고침시 데이터의 소실
- 뒤로가기 실행시 데이터의 소실 및 pathname의 변화
- 글 작성 완료 후 페이지 이동시 페이지 이동이 방지됨
해결방안
- router.events 중 routeChangeStart 함수를 이용하여 route의 경로가 변경되시 시작할때 이동확인 모달과 강제로 error를 발생시켜 페이지 이동을 막는다.
- 새로고침은 event beforeunload 를 사용하여 페이지 이동방지 팝업으로 막는다.
- 뒤로가기 역시 route 변경이기 때문에 1번과 같은 방법으로 막는데, 링크는 router.push 로 인해 변경됨. 현재의 pathname 과 router.asPath 를 비교하여 다를 경우 링크를 변경해준다.
- 글 완료후에 페이지 이동이 생기는데 이때도 페이지 이동방지 모달이 발생하게된다. 글 작성 완료시 완료 확인체크 state를 변경시켜 글 작성완료시 true를 반환하게 하여 페이지 이동을 시킨다.
Dynamic Router 로 보내준 query 를 사용할 수 없는 문제
- 문제
- dynamic router로 query를 보낸 후에 받아서 해당 쿼리로 데이터를 불러오는데, 새로고침시에는 보내준 쿼리가 없기 때문에 데이터를 불러오지 못하는 현상
- 해결방안
- sessionStorage를 이용하여 처음에 받은 쿼리를 저장하여 사용
긴 로딩타임
🛫 서비스 성능개선
- Next.js <Image>를 사용하여 이미지 최적화를 하여 Perfomance를 최대 30% 개선하였습니다.
- <button>과 <Link> 태그에 고유한 aria-lable값을 부여하여 Accessibility를 최대 27% 개선하였습니다.
메인페이지
개선 전
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F18a89f08-bb69-448d-8d9b-00b6a8653e0b%252F%2525E1%252584%252586%2525E1%252585%2525A6%2525E1%252584%25258B%2525E1%252585%2525B5%2525E1%252586%2525AB.png%3Ftable%3Dblock%26id%3Dcf650685-aed5-47c2-94e1-f52c188a0978%26cache%3Dv2&w=3840&q=75)
개선 후
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F81d45506-5f24-431a-b949-9f2de9357396%252F%2525E1%252584%252586%2525E1%252585%2525A6%2525E1%252584%25258B%2525E1%252585%2525B5%2525E1%252586%2525AB.png%3Ftable%3Dblock%26id%3Df52dd6dc-5d82-4d57-86e1-20442c70fa0d%26cache%3Dv2&w=3840&q=75)
글쓰기페이지
개선 전
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Fe95b5096-e888-4372-82d8-7e9b16ea4da7%252F%2525E1%252584%252580%2525E1%252585%2525B3%2525E1%252586%2525AF%2525E1%252584%25258A%2525E1%252585%2525B3%2525E1%252584%252580%2525E1%252585%2525B5.png%3Ftable%3Dblock%26id%3D081107d2-f5d3-493a-8dc0-39f649a23522%26cache%3Dv2&w=3840&q=75)
개선 후
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F07ba2087-10ae-4cfb-8ee4-3dbbd12056a0%252F%2525E1%252584%252580%2525E1%252585%2525B3%2525E1%252586%2525AF%2525E1%252584%25258A%2525E1%252585%2525B3%2525E1%252584%252580%2525E1%252585%2525B5.png%3Ftable%3Dblock%26id%3De21f0261-5f56-4ef2-9c96-359f3038fe58%26cache%3Dv2&w=3840&q=75)
상세페이지
개선 전
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F02e42d59-0d40-4003-bab5-a884abe2e383%252F%2525E1%252584%252589%2525E1%252585%2525A1%2525E1%252586%2525BC%2525E1%252584%252589%2525E1%252585%2525A6.png%3Ftable%3Dblock%26id%3Dbcc4ef5f-0c9e-4179-831c-520ed0671dc2%26cache%3Dv2&w=3840&q=75)
개선 후
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Ffa50fc01-d44f-46d0-877c-daeeb5df6b02%252F%2525E1%252584%252589%2525E1%252585%2525A1%2525E1%252586%2525BC%2525E1%252584%252589%2525E1%252585%2525A6%2525E1%252584%252591%2525E1%252585%2525A6%2525E1%252584%25258B%2525E1%252585%2525B5%2525E1%252584%25258C%2525E1%252585%2525B5.png%3Ftable%3Dblock%26id%3De9a9cb00-d576-4388-b4d6-4672c7befd3f%26cache%3Dv2&w=3840&q=75)
마이페이지
개선 전
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F47789c60-58a7-4cb5-8155-94b1a68fe3bd%252F%2525E1%252584%252586%2525E1%252585%2525A1%2525E1%252584%25258B%2525E1%252585%2525B5%2525E1%252584%252591%2525E1%252585%2525A6%2525E1%252584%25258B%2525E1%252585%2525B5%2525E1%252584%25258C%2525E1%252585%2525B5.png%3Ftable%3Dblock%26id%3D8c83f364-5d07-4843-b8ca-842d1947dfa5%26cache%3Dv2&w=3840&q=75)
개선 후
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F42143156-1cbd-4c4e-bc98-671bc6f6868f%252F%2525E1%252584%252586%2525E1%252585%2525A1%2525E1%252584%25258B%2525E1%252585%2525B5%2525E1%252584%252591%2525E1%252585%2525A6%2525E1%252584%25258B%2525E1%252585%2525B5%2525E1%252584%25258C%2525E1%252585%2525B5.png%3Ftable%3Dblock%26id%3Dc9ecd637-083e-466e-899d-c09fd21deea3%26cache%3Dv2&w=3840&q=75)
유저페이지
개선 전
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252F21c9ce61-c403-4627-a76e-bee46d6fbc0b%252Fuserpage_version_1.7.png%3Ftable%3Dblock%26id%3D394e5f80-d7ec-4eca-a2cf-b2c7a43b95e0%26cache%3Dv2&w=3840&q=75)
개선 후
![notion image](https://inblog.ai/_next/image?url=https%3A%2F%2Fwww.notion.so%2Fimage%2Fhttps%253A%252F%252Fs3-us-west-2.amazonaws.com%252Fsecure.notion-static.com%252Faba7b92a-7392-4d7d-8d3a-b21e5f730859%252F%2525E1%252584%25258B%2525E1%252585%2525B2%2525E1%252584%25258C%2525E1%252585%2525A5%2525E1%252584%252591%2525E1%252585%2525A6%2525E1%252584%25258B%2525E1%252585%2525B5%2525E1%252584%25258C%2525E1%252585%2525B5.png%3Ftable%3Dblock%26id%3D4c0ae154-6d67-4601-ad3e-5d1dd9fa1ff2%26cache%3Dv2&w=3840&q=75)
Share article
Subscribe to our newsletter