해당 프로젝트는 프론트엔드 4명 백엔드 2명으로 이루어진 팀으로 진행했으며,
각자 로그인, 회원가입 / 메인 / 제품목록 / 제품상세 / 장바구니 / 위시리스트 페이지로 역할을 분배하였다. 필자는 제품목록과 위시리스트는 담당했다.
컨버스 제품 목록은 1,2,3 페이지로 나누는 pagination 방식이 아닌 스크롤를 내려 일정 위치에 도달하면 제품을 추가적으로 보여주는 무한 스크롤 구조였다.
infiniteScroll = (e) => {
// documentElement, body 속성의 scroll 값이 다를 수 있다고 하였고
// 다를시 둘 중에 최대값을 사용하는 것이 안전하다는 포스팅을 참고하였음.
let scrollHeight = Math.max(
document.documentElement.scrollHeight,
document.body.scrollHeight
);
let scrollTop = Math.max(
document.documentElement.scrollTop,
document.body.scrollTop
);
let clientHeight = document.documentElement.clientHeight;
if (scrollTop + clientHeight === scrollHeight) {
this.pagination(); // 데이터 호출 함수
}
};
fetch
함수를 실행시키고자 하였다."처음부터 데이터 전체를 받아오는 게 아닌데 어떻게 총 수량을 카운트 하는거지?"
라는 의문이 생겼고, 개발자도구를 확인해보니
백엔드에서 그때 그때 데이터를 불러오는 것이 아닌 처음부터 모든 제품 데이터를 가져와 프론트엔드에서 직접 필터링한 내용을 기반으로 UI를 구현했다는 것을 알 수 있었다.
pagination = () => {
// 먼저 전체 데이터와 보여줄 데이터를 나누어 관리하였다.
const { wholeProducts, products } = this.state;
// 보여줄 제품이 없을 때는 멈추게끔 조건문 설정
if (wholeProducts.length > products.length) {
// 로딩 이미지 관련 함수
this.setState(
{
loadingStatus: !this.state.loadingStatus,
},
// 전체 데이터에서 14개씩 호출
() => {
let result = wholeProducts.slice(
products.length,
products.length + 14
);
// 로딩이미지를 일정 시간 보여줄 수 있게끔 setTimeout
setTimeout(
() =>
this.setState(
{
loadingStatus: !this.state.loadingStatus,
},
// 호출한 데이터를 보여줄 데이터로 병합
() => {
this.setState({
products: [...this.state.products, ...result],
});
}
),
1000
);
}
);
}
};
호버 이벤트에서는 토글 개념과 z-index
활용하여 함수를 만들었는데, 여기에 토글을 이중으로 추가할 수는 없었다. 그래서, 주어진 데이터를 그대로 사용하여 속성을 바꾸어 주는 것이 아닌, 받은 데이터 중에서 메인 이미지를 따로 저장한 뒤에 이벤트가 일어났을 때, 그 데이터 자체를 바꿔주는 원리를 생각했다.
처음에는 js 파일을 만들어 import 하려 했지만 나중에는 state 값을 활용했다
state
활용했던 이유는 lifeCycle 때문이었다.
처음에 js 파일로 만들고 데이터를 수정할 때에는 아무 일도 일어나지 않았다. 데이터만 바뀌고 UI 에 전혀 반영되지 않는 것이다. 그리고 알았던게 setState
이루어지면 렌더링이 다시 된다는 사실이다.
그래서 state
값에 메인 이미지 Url 값을 수정했지만.. 아무일도 일어나지 않았다.
활용하는 이벤트와 값이 자식 컴포넌트에 있기 때문에 데이터 또한 props 이용하여 가져가서 변경했더니 아무것도 일어나지 않았다.
여기서 깨달았던 것은 setState 함수가 일어나는 컴포넌트부터!!! render 가 일어난다는 것이다.
즉, 자식 컴포넌트에서 setState 일어나도 부모 컴포넌트에는 render 일어나지 않아 아무 반응이 없는 것이다.
그래서 데이터를 props로 가지고 내려가는 것이 아닌!!
해당 이벤트와 값을 자식에서 부모로 가지고 올라가서 setState 함수를 실행시켜주어야 바뀐 데이터가 UI에 반영될 수 있었다.
여기서 중요한 점은 부모-자식 관계를 이해하여 이벤트가 일어났을때 render가 되어야 하는 지점을 정확하게 파악하고 있어야 한다는 점이다.
해당 원리를 쉽게 풀 수 있도록 추후에 redux
개념을 학습할 예정이다.
제품 목록 페이지에서 좌측 수평 필터링 레이아웃에 숨기기 기능이 있다.
각각 별개로 작동하지만 동일한 기능이기에 간략하게 코드 구조를 고민하였다.
기본적인 토글 구조를 기반으로 하는데 메뉴탭과 다른점은 서로를 교체, 대체하는 것이 아닌 각각의 기능이 별개로 작동한다는 점이다. 그래서 각각 고유 값을 부여해주어야 한다. 그래서 state
값에 배열을 넣고, 필터 메뉴의 개수 만큼 Boolean
값을 넣었다. 그리고, 각 메뉴별로 자신에게 해당하는 값을 바라보게 하여 className
을 변경해주었다.
// 메뉴에 해당하는 인덱스 값을 가져와 이에 대응하는 위치의 state 값을 바꿔주는 함수
hideFilter = (e) => {
this.setState({
hideFilterImage: [
...this.state.hideFilterImage.slice(0, e),
!this.state.hideFilterImage[e],
...this.state.hideFilterImage.slice(e + 1),
],
});
};
post
통신을 했다. // 위시리스트 보내는 함수
handleHeart = (mainId) => {
fetch(`${secondAPI}/account/wishlist`, {
method: "POST",
headers: {
Authorization: localStorage.getItem("token"),
},
body: JSON.stringify({
id: mainId,
}),
})
};
// 위시리스트 받는 함수
getWishList = () => {
fetch(
`${API}/account/wishlist`,
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
)
.then((res) => res.json())
.then((res) => {
this.setState({
wishlist: res.wishlist,
});
});
};
location
개념을 활용했다.location
이나 match
모두 url 주소를 활용한다는 개념이고 용도 명확히 나뉘지 않는다는 느낌을 받았다.location
개념을 활용할 때에는 Route.js 주소에 url/:id 이런식으로 뒤에 붙여서는 안된다.this.props.location
값이 인식되지 않는다. 이것은 match.params
활용할 때에 설정하는 주소이다. getDataInitial = () => {
// url 주소 중에서 활용할 문자열을 가져오는 식이다.
const categoryId = this.props.location.search.split("=")[1];
// 이 문자열을 활용하여 쿼리스트링을 구성한다.
fetch(
fetch(`${firstAPI}/products?sub_category_id=${categoryId}`
{
headers: {
Authorization: localStorage.getItem("token"),
},
}
)
.then((res) => res.json())
.then((res) => {
let result = res.products.slice(
this.state.products.length,
this.state.products.length + 14
);
});
);
};
짧게 느낀 점을 애기하자면
개인적으로 굉장히 재밌었다. 하하호호 거리며 진행했던 것은 아니지만, 이렇게 치열하게 밤늦게까지 어떤 작업을 했던 기억이 정말 오랜만이었다. 앞으로 이런식으로 살아야겠다는 생긱이 든다. 또 다음 프로젝트가 있겠지만 이번 기간동안 함께 해주신 그리고 모든 동료들에게 감사하다는 말씀을 드리고 싶다.
항상 팀원들과 프로젝트 진행 상황을 확인하고 챙겨주신 PM 상호님
시각적으로 화려한 부분아 아니어서 답답하셨을텐데 묵묵히 자기 역할을 가장 완벽하고 성실하게 수행해주신 호균님
일과 병행하고 장비가 망가지는 해프닝이 있어도 지치는 기색 없이 프로젝트에 열의를 보이며 함께해주셨던 에이스 영빈님
너무나도 든든하게 저희가 받쳐드리지 못할 정도의 역량을 보여주신 두 백엔드 팀원 경훈님과 수정님
이 분들과 함께 했어서 행복할 수 있었던 것 같습니다. 함께 해주셔서 감사하고 영광이었습니다!
유레카 짤ㅋㅋㅋ딱 병진님이네요,,