위코드에서 가장 기대했던 것 중 하나! 프로젝트!
프로젝트 때 쯤이면 나도 어느정도 자신있는 수준이겠지라고 생각했는데
프로젝트는 순식간에 눈앞에 다가와있었다.
난 아직 준비가 안됐는데... 걱정할 틈도 없이 시작된 1차 프로젝트 🔥
우리 팀은 다이어트 쇼핑몰인 다신샵을 클론코딩하게 되었다.
공통 - Git, ESLint, Prettier
Frontend
React, React-Router, javascript, SCSS
Backend
Node.js, Express, MySQL, Prisma, Bcrypt, JWT, Postman API
프론트엔드 : 리스트 컴포넌트 (메인페이지, 리스트 페이지)
백엔드 : 장바구니 API (C, R, U, D)
C,R,U,D를 모두 구현해보고 싶었는데, 장바구니를 맡게 되어 좋았다.
나는 눈 앞에 있는 나무만 보고 있었다는 걸 크게 느꼈다.
react와 node를 배우면서 미션을 하나하나 따라가는 것에 급급했던 걸 느끼긴 했지만 프로젝트를 해보니까 프로젝트의 전체적인 흐름을 이해하는 것이 무엇보다 중요하다는 생각이 들었다.
여러 페이지에 반복적으로 사용되는 컴포넌트도 그렇고, 프론트와 백을 붙일 때도 전체적인 그림을 이해한 후 내가 맡은 부분을 이해해야 하는 것이 맞는 것 같다.
지금보다 더 코알못이었던 예전의 나는 개발자는 코드만 치는 줄 알았다.
하지만 프로젝트를 경험하면서, 개발자 - 커뮤니케이션 = 0이라는 걸 느꼈다.
엄청나게 공들인 초기세팅도, 같은 시간에 모여서 받았던 머지도 순간순간의 작은 커뮤니케이션을 놓치면 error
와 conflict
가 되니까, npm start를 할 때마다 두근거렸던 것 같다.
세상 그 어떤 직업보다 서로 간의 커뮤니케이션이 중요하지 않나 싶다.
위벅스나 몬스터 과제로 구현해봤던 부분이라 구조는 쉽게 짤 수 있었는데, 1) 카드마다 좋아요 버튼을 구현하고 그 상태를 백엔드에 넘기는 것 2) 각 페이지마다 다르게 불러와지는 리스트를 구현하는 것이 내가 맡은 프론트엔드에서 나에게 산처럼 느껴졌다.
다신샵은 메인페이지, 카테고리(메인-서브), 베스트나 신상품같은 리스트 페이지에서 각각 다른 상품 데이터를 리스트로 불러오고 있었다. 특히 카테고리도 메인, 서브 카테고리로 세분화되었고 각 카테고리를 클릭했을 때 불러오는 리스트가 달랐다.
props와 동적 라우팅을 활용해 이를 구현해야 했다.
처음에는 if, else if 를 여러개 써서 각 if문 안에서 fetch를 통해 데이터를 가져오고 filter함수로 어떤 데이터를 리스트화 할 것인지 구현했다.
백엔드에서 주는 데이터에 맞게 수정이 필요했다.
코드리뷰에서 멘토님이 지금은 페이지가 크게 4개라 절대적으로 많은 편이 아니지만 페이지가 더 많아질 것을 대비해 fetchFunction으로 fetch함수를 객체화해놓고 사용하는 방법을 알려주셨고 적용해보았다.
fetchFunctions = {
mainpage: () => {
fetch(`/list/mainpage`)
.then(res => res.json())
.then(res => {
this.setState({ products: res.DATA });
});
},
search: () => {
const { search } = this.props.location;
const queryObj = queryString.parse(search, { decode: 'false' });
const { words } = queryObj;
fetch(`/list?value=${words}`)
.then(res => res.json())
.then(res => {
this.setState({ products: res.DATA });
});
},
list: () => {
const { main, sub } = this.props.match.params;
if (sub === undefined) {
fetch(`/list/main/${main}`)
.then(res => res.json())
.then(res => {
this.setState({ products: res.DATA });
});
} else {
fetch(`/list/sub/${sub}`)
.then(res => res.json())
.then(res => {
this.setState({ products: res.DATA });
});
}
},
category: () => {
const { sort } = this.props.match.params;
fetch(`/list/${sort}`)
.then(res => res.json())
.then(res => {
this.setState({ products: res.DATA });
});
},
};
componentDidMount() {
const { page } = this.props;
this.fetchFunctions[page]();
}
백엔드에서는 장바구니 API를 맡았다.
쉽지 않았지만 CRUD를 전부 해보고 싶었어서 재밌게 할 수 있었다.
model단에서 sql문 짜는 것은 나름 재미가 있었지만 mvc 패턴 각 부분에서의 에러처리 아직 능숙하게 다루지 못하는 것 같다는 생각이 많이 들었다.
코드가 happy하면 내 미래가 안 happy하다.
장바구니 추가 API
기본적으로 장바구니의 c.r.u.d는 모두 로그인 한 상태에서만 사용가능하게 구현했다.
즉, 로그인한 상태에서만 장바구니 추가, 조회, 수정, 삭제 기능이 가능하다.
장바구니에 담긴 품목 개수 조회 API(로그인 상태에서만 조회 가능)
장바구니 API
mysql> desc carts;
+------------+------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+------+------+-----+---------+----------------+
| id | int | NO | PRI | NULL | auto_increment |
| quantity | int | NO | | NULL | |
| user_id | int | NO | MUL | NULL | |
| product_id | int | NO | MUL | NULL | |
+------------+------+------+-----+---------+----------------+