클론 사이트
배민문방구 - https://brandstore.baemin.com/
- 배민문방구는 주식회사 우아한 형제들의 사이트로 재미있게 사는 경험을 추구하는 문구, 리빙, 책, 콜라보 한정판 제품을 판매하며 고유의 색감과 깔끔한 디자인과 탄탄한 기본적인 기능들이 합쳐져있는 온라인 커머스 사이트이다
시연 영상
https://www.youtube.com/watch?v=JQFqtvcOhj0
AWS 배포 : 88문방구 (http://3.137.123.220:8000/main)
GitHub
https://github.com/cks612/32-1st-88stationery-frontend.git
Team 소개
- 팀 명 : 88문방구
- 의미 : 수많은 이름이 나와서 엄청 고민했지만 PM분이 88년생이고 입에 착 달라붙는 이름 같아서 팀 명을 88문방구로 정했다
- FrontEnd : 덕우님 / 현석님 / 수광님 / 나
- BackEnd : 남규님 / 예찬님
기술 스택
BackEnd
- Python
- Django
- MySQL
- GIT
- AWS
FrontEnd
- React
- React-Router
- SCSS
- Javascript
- HTML
- GIT
- AWS
프로젝트 진행 과정 (Scrum)
총 6명의 팀원이 하나의 프로젝트를 완성하기 위해 스크럼 (Scrum)이라는 프로젝트 관리 방식을 사용하게 되었다. 2주동안 총 2회의 Sprint로 단기 작업 블록을 통해 프로젝트를 진행했다
Planning Meeting
매주 월요일 한 주 동안 진행 사항 및 목표를 설정하는 회의를 진행했다. 첫 주에는 우리가 구현하고자 하는 사이트의 레이아웃을 최대한 많이 완성시키는 목표를 정해서 계획을 세웠고, 둘째 주에는 첫째 주에 완성하지 못했던 부분들과 백엔드와의 협업을 통해 목데이터가 아닌 실제 백단에서 보내주는 데이터로 구현하는 것으로 계획을 세웠다
Daily Standup Meeting
매일 아침 10시에 프론트 백엔드 상관없이 함께 전날 각자의 업무 내용과 진행 상황에 대해 얘기하며 하루하루 무엇을 진행할지 공유하는 회의를 진행했다. 우리 팀은 소통에 어려움이 없었던 것 같다. 작업을 진행하면서 서로에게 필요한 데이터나 기타 정보들을 그때그때 협의하면서 소통을 진행하다 보니 순조롭게 진행됐다
Communication Tool
- Slack : 소통
- Trello : 프로젝트 일정관리, 백엔드 프론트엔드 진행 현황 공유
협업 프로젝트이다 보니 서로의 작업 상황이나 일정 등을 서로서로 공유해야 되기 때문에 Trello를 사용했다
- Backlog (앞으로 해여할 것들)
- To Do (이번주에 해야할 것들)
- In Progress (현재 진행 중인 것들)
- In Review (코드와 기능 리뷰)
- Done (완료)
- utils (기타 공유해서 도움될 것들)
등을 각각 티켓으로 만들고 작업 내용을 공유해 서로 작업 상황이 어떤지 알 수 있었다
Notion : 프론트 / 백 간의 데이터 Api, fetch 구현 방안 정리 및 공유
- 매일매일 회의를 하면서 노션에다 작업 사항들과 회의록을 작성했다
목표
팀 목표
우리 팀은 총 2가지의 주요 목표를 세웠다. 첫 째는, 이건 “팀 프로젝트"이기 때문에 좋은 협업 분위기를 만들자였다. 서로 각자 다른 성격과 상황이 있기 때문에 예민해진 상황에서는 트러블이 있기 마련이다. 분위기 좋은 팀을 만들수록 결과물도 잘 나오기 때문에 1차 목표로 잡았다. 두번째는, 기능구현 즉, “우선적인 목표를 달성" 후 추가기능 말고 팀원들을 돕기였다. 내것만 열심히 하지 말고 우리는 팀이니까 서로서로 물어보고 배우는 팀이 되었으면 좋겠어서 2차 주요 목표로 잡았다. 배민문방구는 상대적으로 복잡하지 않은 사이트인 것 같다. 하지만 그럴수록 필수적인 기능들을 탄탄히 만드는게 중요하다! 기본에 충실하면서 모르는거 있으면 다 같이 알려주면서 즐겁게 개발하기
개인 목표
팀 프로젝트는 '나만'이라는 단어는 없다. '나만 잘하면 돼'라는 생각을 하는 순간 그건 팀 프로젝트가 아니고 개인 프로젝트라고 생각한다. 바빠도 서로 뭘 했는지, 어는 부분이 어려웠는지 또는 문제가 있는지에 대한 내용이 공유가 되어 다 같이 배우면서 항해하는 모습이야말로 협업이고 팀 프로젝트이다
그래서 세운 나만의 목표는
1. 시간이 제한적이고 팀 프로젝트인 만큼 며칠동안 시간 소비하지 말고 잘 안되면 혼자 끙끙대지 말고, 물어보면서 같이 해쳐나가자
2. 욕심내지 말기, 필수 기능 구현을 하기도 전에 너무 욕심내지 말고 팀원들한테도 이거 해보자 저거 해보자 요구하지 말자. 시간이 남으면 얼마든지 보완하고 할 수 있다
기능 구현
모델링 (공통)
내가 맡은 기능
- Nav바
- Side바
- Search바 및 검색 기능 (백엔드와 실시간)
- 덕우님이 구현하신 main 페이지 안에 들어갈 items 캐러셀
- 카테고리 조건별 sorting
- SCSS (@mixins 와 variables.scss 활용하기)
- 수광님이 만드신 로그인 기능 모달화
- AWS 배포
Nav바
공통으로 사용될 컴포넌트인 상단 Nav 바부터 시작했다. 배민문방구 사이트를 보면서 레이아웃을 짜고 기능으로 넘어갔다. Nav 바는 기능이 많지 않았지만 스크롤이 제일 위에 있을때는 배경을 투명하게 하고 밑으로 조금이라도 움직이면 border와 opacity가 발생한다
Side바
Nav바 다음으로 공통 컴포넌트인 Side바를 구현했다. 버튼 클릭시 오른쪽에 숨어있던 side바를 right:0 으로 보여주면서 Side바를 제외한 나머지 배경은 어둡게 했으며 X를 굳이 누르지 않고 배경을 눌러도 side바가 풀리게 만들었다. Side바가 나올시 스크롤과 뒷 배경의 카테고리들이 눌리지 않게 body에다가 overflow: hidden 과 배경에다가는 z-index를 설정해 카테고리들이 눌리지 않게 만들었다
Search 바
search 버튼 클릭시 위에 있던 search바를 자연스럽게 내려오게 만들었다. 처음에는 상수데이터로 검색 기능을 구현했지만 백엔드와의 통신으로 기능을 수정했다. 한 번에 데이터를 받아와서 필터링 하는게 아니라 실시간으로 입력값이 바뀔 때 마다 백단과의 fetch를 통해 데이터를 받아와서 뿌려주는 기능을 구현했다
main 페이지 안에 들어갈 items 캐러셀
배민문방구에는 메인 페이지에 캐러셀이 두 개가 들어있다. 덕우님이 만들어 놓으신 메인 페이지 캐러셀 밑에 내가 만들고 싶었던 캐러셀을 구현 후 붙여넣었다. 이미지 hover시 뒤에 있던 이미지를 애니메이션으로 나오게 하고 오른쪽 버튼도 나오게 했다. 배민문방구에서도 한 번 넘기면 끝이라 넘길시 반대편 버튼을 나오게 구현을 했다.
카테고리 조건별 sorting
카테고리 별로 가격이 높은 순 / 낮은 순 / 신상품으로 sorting되는 기능을 구현했다. 초반에는 백엔드에서 데이터를 모두 받아와 프론트단에서 sorting을 했지만 비효율적인 생각이 들어 프론트에서는 요청만 보내고 백단에서 sorting작업을 한 후 프론트에서 뿌려주기만 하는 기능을 구현했다
로그인 기능 모달화
수광님이 만들어 놓으신 로그인 기능 페이지를 모달화로 만들었다. 처음으로 {children}이라는 개념을 사용해 레이아웃을 수정하고 Side바와 마찬가지로 나오면 주변은 어둡게 만들고 스크롤과 클릭이 안 되게 구현했다
📍 기억에 남는 코드
리액트로 페이지를 팀으로 처음 구현해 보려고 하니 욕심도 나고 어려움 점이 정말 많았던 것 같은데 그 중에 기억에 남는 코드는
Search 기능
function Search({ isSearchOn, handleSearchBarOn }) {
const [userInput, setUserInput] = useState("");
const [userSearch, setUserSearch] = useState([]);
const handleChange = e => {
setUserInput(e.target.value);
};
const filterInputValue = userSearch.filter(search => {
return search.name.includes(userInput);
});
useEffect(() => {
fetch(`${config.search}?search=${userInput}`)
.then(response => response.json())
.then(result => {
setUserSearch(result.searched_products);
});
}, [userInput]);
return (
<div
className={
isSearchOn ? "searchBarContainer action" : "searchBarContainer base"
}
>
<div className="searchBarWrapper">
<div className="searchBarHeader">
<input
type="text"
placeholder="검색어를 입력해주세요"
onChange={handleChange}
/>
<i className=" fa fa-light fa-magnifying-glass fa-2x" />
</div>
<div className="searchResultContainer">
{userInput.length > 0 ? (
filterInputValue.map(list => {
return (
<SearchItems
key={list.product_id}
list={list}
handleSearchBarOn={handleSearchBarOn}
/>
);
})
) : (
<div className="searchBarRecentContainer">
<section className="searchBarRecentItems">
<h3>검색어를 입력해주세요</h3>
</section>
</div>
)}
</div>
<i
className="fa fa-duotone fa-xmark fa-2x"
onClick={handleSearchBarOn}
/>
</div>
</div>
);
}
처음으로 백단과의 통신으로 실시간 입력 후 결과를 받아와서 뿌려주는 코드이다. 처음에는 fetch받지 않고 모든 데이터를 받아와서 프론트단에서 필터링을 해줬지만 데이터 양이 10만개 100만개가 되면 받아오는 시간도 시간이고 너무 비효율적이다. 그래서 검색 할 때만 입력값에 따라 결과만 보여주면 되니까 입력 할 때마다 백단에서 필요한 정보를 보내주고 받아와서 state값에 저장을 하니까 리렌더링이 되면서 가져온 값을 필터링 후 뿌려줄 수 있었다.
Config.js와 JSX Body 스타일 주기
export const MAIN_URL = "<http://3.39.118.217:8000/>";
export const config = {
login: `${MAIN_URL}users/signin`,
question: `${MAIN_URL}questions/question`,
answer: `${MAIN_URL}questions/answer`,
main: `${MAIN_URL}main`,
category: `${MAIN_URL}products/category`,
goods: `${MAIN_URL}products`,
carts: `${MAIN_URL}orders/carts`,
search: `${MAIN_URL}search`,
orders: `${MAIN_URL}orders`,
signup: `${MAIN_URL}users/signup`,
};
import React from "react";
export default function AsideGlobalChange() {
return (
<style jsx="true">{`
body {
overflow: hidden;
}
`}</style>
);
}
config.js 쓰기 전에는 fetch 하는 모든 url을 적어줘야 했지만 그렇게 되면 fetch를 할 때마다 url을 읽어주고 동작하는 방식이기 때문에 비효율적이다. 이렇게 한 번에 관리를 하면 해당하는 객체의 키 값에만 접근하면 되기 때문에 관리하기도 편하다. Side바와 로그인 모달화 처럼 body에 overflow hidden을 줘야 스크롤이 안 먹기 때문에 side바나 로그인 창을 눌렀을 때 실행되는 컴포넌트이다. style jsx=”true”로 놓고 바로 body에다 overflow:hidden 이라는 스타일을 줬다. 리액트는 직접적으로 DOM을 접근하면 안 되기 때문에 이렇게 document.이 아니라 이런식으로 body에다가 스타일을 줄 수 있다.
아쉬운 점
백엔드와 서로 데이터를 주고 받을 때, 어떤 데이터를 어떻게 주고 박을지 논의하는 시간을 많이 보내지 않아서 아쉬웠다. 이번 프로젝트를 진행하다 보니 데이터 모델링이 너무나도 중요하다고 느꼈다. 다행히도 저희 백엔드 분들이 워낙 잘 해 주시고 원하는 형식대로 만들어 주셔서 백엔드에서는 문제가 1도 없었다. 오히려 프론트가 문제였... 2차 프로젝트에서는 초반에 백엔드와 많은 얘기를 하면서 데이터 구조를 같이 논의해 봐야겠다고 생각한다.
마무리
그렇게나 기대와 걱정했던 첫 프로젝트가 끝났다. 이번 2주는 정말 순식간에 빠르게 지나갔다. 초반에는 걱정했지만 발표 전날에 끝나는 걸 보면서 우리도 할 수 있구나 라는 자신감이 생겼던 것 같다. 물론 좋은 팀원들을 만난것도 있지만 하루도 빠짐없이 나와서 밤도 새고 열심히 한 내 자신한테도 박수를 보내고 싶다. 힘든 기간이었지만 팀원들 덕분에 힘내서 재밌게 해낼 수 있었던 것 같고 결과물도 우리 팀이 1등이라는 자부심도 있다. 그만큼 결과물이 잘 나왔기 때문이다. 2차 프로젝트를 통해 더 많은 소통과 하고싶은 기능들을 구현하면서 더욱 더 성장하고 싶다! 88문방구 최고!