브랜드 목록 필터링 : 전체 및 존재하는 브랜드 목록 필터링 기능 구현
(1)
localStorage
에 저장되어 있는 상품 목록 중 brand 값에 대해서 중복을 제거(Set 사용
)하여 brand, brandFilter 값에 저장시킨다.
componentDidMount() {
const visitedItem = getProducts();
this.setState({
products: visitedItem,
});
const myStorageBrand = new Set(visitedItem.map((item) => item.brand));
this.setState((prev) => ({
...prev,
brand: [...myStorageBrand],
brandFilter: [...myStorageBrand],
}));
}
(2) 브랜드 checkbox를 클릭하면, 넘겨져 온 값을 brandFilter에 저장한다.
setBrandFilter = (brandList) => {
this.setState({
brandFilter: brandList,
});
};
(3) 브랜드를 checkox 형식으로 보여준다. 클릭하면 해당 브랜드 값을
e.target.checked
에 따라서 brandFilter값에 넣고/빼준다.
{brand.map((name, idx) => (
<CheckBox
key={`brand${idx}`}
value={name}
checked={filter?.includes(name)}
onChange={(e) => {
if (e.target.checked) {
onChange([...filter, name]);
} else {
filter.length === brand.length
? onChange([name])
: onChange(filter.filter((opt) => opt !== name));
}
}}
/>
))}
(4) brandFilter값에 있는 브랜드만 보여주도록 한다.
products.filter((p) => brandFilter.includes(p.brand))
관심 없는 목록 필터링 : 관심 없는 상품 숨기기 체크박스 기능 구현
관심 없는 상품 숨기기를 클릭하면 아래
toggleDisLikeFilter
를 실행하고 showDisLikeFilter값에 따라 필터링을 적용시킨다.
toggleDisLikeFilter = () => {
this.setState((prev) => ({
...prev,
showDisLikeFilter: !prev.showDisLikeFilter,
}));
};
products.filter((p) => (showDisLikeFilter ? p.disLike === false : p))
[상품 목록 페이지]
🔻 public/data/data.json 파일 불러오기
state = {
allProducts: [],
};
async componentDidMount() {
const productData = await getProductJsonData();
const editedProductData = productData.map((item, idx) => {
item.id = `prod${idx}`;
item.disLike = 0;
item.visitedDate = "";
return item;
});
this.setState({
allProducts: editedProductData,
});
}
export const getProductJsonData = async () => {
const response = await fetch("data/data.json");
const data = await response.json();
return data;
};
[상품 상세 페이지]
❌ url에는 id값만 넘기면 된다. 아래의 방법은 좋지 않다고 하셨다. ❌
상품목록에서 아이템을 클릭하면 상세페이지로 이동하는데, 이때 state 값에 원하는 값을 넘겨 줄 수 있다.
history.push({
pathname: `/productdetail/${id}/${title}/${brand}/${price}/${disLike}`,
state: { allProducts: allProducts },
});
🔻 '랜덤 상품 조회' 버튼 클릭 시 현 상품 제외하고 랜덤 로드 기능 구현
: 상품아이디를 랜덤으로 가져와서, 중복되거나 관심없는 상품일 경우 다시 콜백
handleRandomClick = () => {
const { allProducts, product } = this.state;
const randomNum = Math.floor(Math.random() * (allProducts.length - 1));
const { title, brand, price, disLike } = allProducts[randomNum];
if (`prod${randomNum}` === product.id || disLike) return () => this.handleRandomClick();
history.push({
pathname: `/productdetail/prod${randomNum}/${title}/${brand}/${price}/${disLike}`,
state: { allProducts },
});
const productData = getProductData(this.path);
this.setState({
product: productData,
});
};
🔻 '관심 없음' 버튼 클릭 시 랜덤 로드 기능 구현
: 현재 상품을 가져와서 disLike값을 true로 변경
handleDisLikeClick = () => {
const products = getProducts();
const currentData = products[products.length - 1];
currentData.disLike = true;
products.splice(products.length - 1, 1, currentData);
setProducts(products);
this.handleRandomClick();
};
🔻 상품 상세 조회 시 이력 데이터 누적 기능 구현 & 동일 상품 조회 시 최신 데이터 갱신 기능 구현
: isExist로 확인 후 갱신 및 누적 기능 구현
: getProducts()
localStorage.getItem() 함수
: setProducts()
localStorage.setItem() 함수
const products = getProducts();
const currentItem = this.state.product;
const isExist = products
.map((product, index) => (product.id === currentItem?.id ? index : undefined))
.filter((el) => (el !== undefined ? `${el}` : null));
if (isExist.length > 0) products.splice(isExist[0], 1);
const newData = products.concat(currentItem);
setProducts(newData);
[상품 조회 이력 목록 페이지]
🔻 00시 기준 상품 조회 이력 및 관심 없는 상품 목록 초기화 기능 구현
: moment를 설치하여 현재시간이 "00:00:00"인 경우 clearProducts
(localStorage 초기화를 실행하는 함수)를 실행한다.
componentDidMount() {
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
const midnight = "00:00:00";
let nowTime = null;
nowTime = moment().format("HH:mm:ss");
if (nowTime === midnight) {
clearProducts();
this.setState({
products: [],
});
}
}
🔻 정렬 기능: 최근 조회 순, 낮은 가격 순 팝업 기능 구현
: 최근 조회 순 버튼에 id = recent
, 낮은 가격 순 버튼에 id = low
를 설정했다.
: 최근 조회 순 Date type 비교는 new Date(...).getTime() 형변환
하여 비교한다.
: 낮은 가격 순 Number로 형변환
하여 비교한다.
[참고] 오름차순 정렬 (1,2,3,4,...)
arr.sort(function(a, b) { return a - b; });
[참고] 내림차순 정렬 (...,4,3,2,1)
arr.sort(function(a, b) { return b - a; });
handleSort = (e) => {
const { id } = e.target;
const { products } = this.state;
const sortedState = products.sort((prev, next) =>
id === "recent"
? new Date(next.visitedDate).getTime() - new Date(prev.visitedDate).getTime()
: Number(prev.price) - Number(next.price)
);
this.setState((prev) => ({
...prev,
products: sortedState,
}));
this.toggleSortOpen();
};
🔻 '관심 없음' 상품 클릭 시 경고 메시지 모달 창 기능 구현
<Overlay isShow={isShow} onClick={() => isShowWarningPopup(false)}>
<TextWrapper>
<span>관심 없는 상품이므로 상세 페이지로 이동할 수 없습니다.</span>
</TextWrapper>
</Overlay>
const Overlay = styled.div`
position: fixed;
display: flex;
align-items: center;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 500px;
height: 800px;
margin: 10px auto;
background-color: rgba(0, 0, 0, 0.4);
visibility: ${({ isShow }) => (isShow ? "visible" : "hidden")};
opacity: ${({ isShow }) => (isShow ? "1" : "0")};
transition: 0.5s;
z-index: 1;
`;
const TextWrapper = styled.div`
${({ theme }) => theme.flexSet("center", "center")}
flex: 1;
background-color: red;
span {
padding: 20px;
color: white;
text-align: "center";
}
`;