일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 시스템콜
- corou
- 나만무
- JavaScript
- 알고리즘
- 프로그래머스
- userprog
- 자바스크립트
- pintos
- 4기
- 자바
- HTML
- 코드트리
- 크래프톤 정글
- Vue.js
- 큐
- 크래프톤정글
- Java
- 백준
- 정보처리기사
- 모션비트
- defee
- Flutter
- CSS
- 스택
- TiL
- 리액트
- 사이드프로젝트
- 핀토스
- 소켓
- Today
- Total
문미새 개발일지
24.09.26 day72 필터 구현, 무한스크롤, 폴링, 화면 처리 본문
다른 필터들은 끝났고 제품 필터와 루틴 필터만 남았다. 제품 필터는 기존에 모아놨던 카테고리들을 없애고 유저의 회원가입 시의 데이터에 맞게 수정했다. 하지만 현재 서버에서 받아오는 데이터에는 기본적으로 하나의 카테고리만 들어가기 때문에 현재 작동 가능한건 중간 부분의 피부별 카테고리만 동작한다.

const filterRankingData = displayItems.filter((item) => {
return subFilter ? item.category === subFilter : true;
});
제품 필터의 경우 현재 category의 부분이 배열이 아닌 한 가지이기 때문에, 카테고리 값이 subFilter로 가져온 value값과 동일하면 true값을 반환하며 해당 값에 맞는 제품들만 필터링 된다.
제품은 api요청을 하는 컴포넌트에서 바로 코드를 수정하면 끝나서 쉬웠으나, 루틴 필터가 진짜 엿같았다.
루틴도 프로젝트 초반에 작성해둔 코드였는데, 예전에 코드짜던 습관이 너무 원망스러웠던게 컴포넌트를 분리하지 않고 먼저 작업한 다음 하나씩 분리해갔으면 금방 끝날 일이였으나 예전에 atomic 디자인에 대한 말을 듣고 해당 방식으로 연습해보면서 손에 익어버렸다. 그리고 api 경우에도 보통 부모 컴포넌트에서 받아와서 자식 컴포넌트에 내려주는 방식이 깔끔하고 좋은데 이번 플젝 때는 최대한 빡빡하게 작업하느라 데이터가 필요한 자식 컴포넌트에 api를 받아와서 작업해버렸다.
덕분에 자식 컴포넌트에서 부모 컴포넌트로 끌어오고 다른 컴포넌트로 보내주고, 이런식으로 코드가 너무 꼬여버렸다. 나중에 코드를 리팩토링할 때가 있으면 그 때 데이터를 순차적으로 내려받게 수정하고 컴포넌트를 분리해야지.

useEffect(() => {
const fetchItems = async (query: string) => {
setLoading(true);
try {
// 루틴 목록 가져오기
const response = await axios.get(
`${backPort}/api/routine${query ? `/search/${query}` : ""}`
);
// 체크박스 필터
const filteringItems = response.data.filter((item: allRoutineData) => {
if (filters.length === 0) return true;
const attrKeyFilter = filters
.filter((filter) => filter >= 1 && filter <= 11)
.every((filter) => item.attr_keys.includes(filter));
const genderFilter =
(filters.includes(12) && item.routine.for_gender === "M") ||
(filters.includes(13) && item.routine.for_gender === "F") ||
(filters.includes(12) &&
filters.includes(13) &&
item.routine.for_gender === "A") ||
(!filters.includes(12) && !filters.includes(13));
const ageFilter =
(filters.includes(14) && item.routine.for_age === 10) ||
(filters.includes(15) && item.routine.for_age === 20) ||
(filters.includes(16) && item.routine.for_age === 30) ||
(filters.includes(17) && item.routine.for_age === 40) ||
(!filters.includes(14) &&
!filters.includes(15) &&
!filters.includes(16) &&
!filters.includes(17));
return attrKeyFilter && genderFilter && ageFilter;
});
// 각 루틴의 아이템 키 가져오기
const updatedItems = await Promise.all(
filteringItems.map(async (item: allRoutineData) => {
console.log("현재 아이템", item);
try {
const itemResponse = await axios.get(
`${backPort}/api/routine/${item?.routine.routine_key}`
);
const firstItemKey =
itemResponse.data.routineDetails[0]?.item_key;
itemAmount = itemResponse.data.routineDetails.length;
return {
...item,
firstItemKey,
};
} catch (error) {
console.error(
`루틴의 제품 목록을 가져오는 중 에러 (${item.routine.routine_key}):`,
error
);
return item;
}
})
);
// 가격 및 개수 필터링 추가
const finalItems = updatedItems.filter((item: allRoutineData) => {
const price = item.routine.price_total;
const itemCount = itemAmount || 1;
const isWithinPriceRange = price >= minPrice && price <= maxPrice;
const isWithinCountRange =
itemCount >= minCount && itemCount <= maxCount;
return isWithinPriceRange && isWithinCountRange;
});
console.log("최종 필터링된 루틴", finalItems);
// setItems(updatedItems);
setItems(finalItems);
setDisplayItems(finalItems.slice(0, itemsPerPage));
} catch (err) {
console.error("아이템 가져오기 실패", err);
setError("데이터를 불러오는데 실패했습니다.");
} finally {
setLoading(false);
}
};
fetchItems(searchQuery);
}, [searchQuery, filters, minCount, maxCount, minPrice, maxPrice]);
루틴 데이터를 api로 요청하는 filterList 컴포넌트로 어떻게든 데이터들을 모아왔다. 이제 api로 루틴 배열을 받아오면서 순차적으로 필터를 거치게 구현했는데, 먼저 서버에서 보내주는 attr_key 배열로 필터 분류를 하는데, 해당 필터는 회원가입 때 체크했던 데이터로 1부터 11까진 problem데이터 12, 13은 gender, 14부터 17까진 age를 따른다.
먼저 체크된 value값이 담기는 filters에 아무런 값이 없다면, 즉, 필터한게 없다면 true값을 반환하며 모든 데이터가 출력된다.
그리고 1부터 11까지 데이터를 확인하면서 attr_key에 필터값이 전부 포함되어 있는지 확인하여 하나라도 없는 값이 있다면 false를 반환하고 전부 포함된다면 해당 데이터를 출력한다.
gender의 경우 12, 13번에 있는데 루틴을 설정할 때 남, 녀 둘다 체크할 수 있게 해놨기 때문에 12, 13번이 모두 체크되었을 때 해당 루틴의 젠더값이 A라면 true값을 반환한다.
age의 경우는 10대 부터 40대까지 4개로 나누어져있고 40대 이상부터는 +로 40으로 포함된다. 그래서 나이에 맞는 값이 있거나 전부 체크되지 않았을 때 true를 반환한다.
이러한 필터 3개가 전부 true값을 반환할 때 체크된 데이터를 출력해준다. 그다음엔 제품의 개수와 가격 필터인데, 이 부분은 위의 필터를 거쳐 루틴 데이터에 저장된 후 해당 값을 가져와서 min값과 max값 안에 들어와 있는 값을 비교해서 화면에 출력해준다. 이 필터는 초반에 UI를 만들 때 미리 만들어둬서 조금만 수정해서 바로 구현했다. 하지만 이 min, max데이터들이 이상한 위치에 있었기 때문에 가지고 오느라 애를 먹었다;;
그리고 무한 스크롤을 한번 확인해봤는데, 무한 스크롤의 방식엔 두 가지가 있다고 한다. 먼저 페이지와 페이지에 보여질 값을 서버에 api로 전달해서 해당 값만을 서버에 받으며 스크롤이 제일 하단에 도달할 때마다 다음 값의 데이터를 api로 쏴준다. 다른 방식은 처음 데이터를 한번에 받아와서 클라이언트에서 일정 개수만 나눠서 화면에 출력하고 스크롤이 발생할 때마다 다음 데이터를 출력하는 방식이다. 데이터의 양이 넘치는 쇼핑몰이나 커뮤니티에선 데이터를 한번에 받아오는 방식은 말도 안되는 방식인 것 같고 화면에 뿌려줄 데이터 값만을 서버에 요청하는 방식이 맞는 것 같다. 하지만 현재 프로젝트의 경우 데이터도 별로 없어 초반 데이터 로드가 짧아 두 번째 방식도 구현이 가능했다. 로직에 대한 학습도 할 겸 괜찮았다.


리뷰 리스트의 폴링의 경우 이전에 재희님한테 폴링에 대한 걸 처음 듣고 찾아봤었다. 일정 주기마다 api로 요청을 하여 데이터를 업데이트 시키는 방식인데, 규칙적인 업데이트가 이루어져야 하는 상태 모니터링이나, 게임에서 플레이어의 위치나 행동을 체크하는 곳에 자주 쓰이는 것 같더라. 이걸 보고 생각난게 정글 안에서 더 정글 쫑문이와 현우님이 설명해준 내용 중에 게임의 레이턴시를 잡기 위해 업데이트 동안 꾸준히 클라의 데이터를 서버에 전송하며 최대한 유저들과의 갭을 줄이기 위해 사용한다고 했는데, 이걸 웹 방식으로 돌리는게 폴링인 것 같다.
찾아본 결과 프론트의 경우엔 많이 작업할 요소는 없었는데 useEffect를 사용해 특정 조건에 재 렌더링을 시키는데 반복적인 작업을 하는 setInterval을 사용해서 일정 주기마다 api를 요청하는 함수를 실행시킨다. 작업한 코드의 경우 30초로 지정헀다.
useEffect(() => {
const interval = setInterval(() => {
fetchReviews();
}, 30000);
return () => clearInterval(interval);
}, [reviews]);
두 개 브라우저를 띄워서 테스트해본 결과 한 곳에서 리뷰를 작성하고 다른 곳에서 일정 시간이 지나 재 렌더링이 발생하며 새로운 리뷰가 뜬 걸 확인할 수 있었다.
그 외에는 모든 페이지에서 데이터가 없어 화면에 출력하지 못할 때 다른 화면을 보여줄 수 있게 만들어놨다.

제품 데이터가 없거나 필터링을 통해 관련 제품이 없으면 해당 화면이 뜬다.

루틴도 제품과 똑같이 해당 루틴이 없을 때의 화면이다.

주문 내역도 이하동문

배송지도 추가했다.
그리고 메인 페이지의 유저에 맞는 타입 루틴을 보여주는 컴포넌트의 경우에도 데이터가 없으면 너무 이상해 보였기 때문에 수정해줬다.
타입루틴은 유저가 로그인했을 때 확인할 수 있는데 로그인을 하지 않았을 때 해당 값을 아예 안보이게 해버리면 메인페이지가 너무 허전해서 로그인하라는 버튼을 만들어서 로그인페이지로 이동하게 했다.

다음으로 로그인을 했으나 본인의 정보에 맞는 루틴이 없을 땐 루틴 페이지로 이동하게 했다. 사실 해당 버튼이 아니여도 더보기를 통해 이동할 수 있지만 있어보이니까 추가했다 ㅎ

이제 남은 부분은 프로필 수정과 데이터베이스의 수정에 맞게 데이터를 추가적으로 받아오는 것과 선택사항 두 개만 남았는데, 앞의 두 개는 api만 있다면 바로 작업할 수 있으나 선택사항 두 개는 주소검색 api와 판매자 모드 페이지 추가다.
판매자 모드는 단순히 제품 추가 페이지의 경우 input 데이터를 추가하는 방식으로 통신하면 금방 하나 주소검색 api의 경우 해당 api에 맞게 DB의 로직도 수정해야 할 수도 있고 프론트의 경우 기존의 UI틀이나 api요청방식을 좀 다르게 수정해야 하기 때문에 제일 마지막으로 보류해놨다. 아마 이것까진 안할 것 같긴 하다.
이제 제품이나 루틴의 데이터를 진짜 상업 사이트처럼 꾸며서 실제로 운영되는 것처럼 작업하려고 한다.
'개발 TIL' 카테고리의 다른 글
24.10.01 day74 자투리 수정 (3) | 2024.10.01 |
---|---|
24.09.30 day73 작업 일지 (1) | 2024.09.30 |
24.09.25 day71 작업 일지 (0) | 2024.09.25 |
24.09.24 day70 취업 설명회 (3) | 2024.09.24 |
24.09.23 day69 작업 일지 (1) | 2024.09.23 |