[React] React로 상품 카테고리 구현하기
아래와 같은 상품 카테고리 필터링을 구현해보자.
✨ 구현 방안
먼저 아래와 같이 json 파일을 만들어 줬다.
// src/data/products.json
{
"productList": [
{
"id": 1,
"name": "[캣닢 장난감] 고양이를 사랑한 오렌지",
"category": "반려동물",
"achievementRate": "35%",
"image": "/assets/images/image001.jpg"
},
{
"id": 2,
"name": "닭 한마리에 1%! 한 팩으로 간편하게 즐기는 닭 특수부위 미식요리",
"category": "푸드",
"achievementRate": "325%",
"image": "/assets/images/image002.jpg"
},
{
"id": 3,
"name": "아이브 스페셜 앨범 정규 1집 Ive IVE 아이엠 I AM 키치 Special",
"category": "음악",
"achievementRate": "89%",
"image": "/assets/images/image003.jpg"
}
...
]
}
Main.jsx 파일에서는 useState를 사용하여 현재 활성화된 탭을 관리하는 activeTab state를 설정했다. 초기값은 “전체”로 설정하였다.
// pages/Main.jsx
...
function Main() {
const [activeTab, setActiveTab] = useState("전체");
return (
<>
<CategoryTab activeTab={activeTab} setActiveTab={setActiveTab} />
<HomeVerticalCard activeTab={activeTab} />
</>
);
}
export default Main;
...
HomeVerticalCard.jsx 파일에서는 ProductsList를 import하고, activeTab에 따라 필터링된 제품들을 보여주는 컴포넌트를 작성했다.
// src/HomeVerticalCard.jsx
import ProductsList from 'data/products.json'; // import
...
function HomeVerticalCard({ activeTab }) {
return (
<CardContainer>
{ProductsList.productList
.filter((product) => activeTab === '전체' || activeTab === product.category)
.map((product) => (
<CardItems key={product.id}>
<Image src={product.image} alt={product.name} />
<Title>{product.name}</Title>
<AchievementRate>
<PointColor>{product.achievementRate}</PointColor> 달성
</AchievementRate>
</CardItems>
))}
</CardContainer>
);
}
export default HomeVerticalCard;
마지막으로, CategoryTab.jsx 파일에서는 카테고리 탭을 관리하는 컴포넌트를 작성했다. 클릭 이벤트가 발생하면 해당 카테고리를 활성화하도록 핸들링하였다.
// src/CategoryTab.jsx
...
const Li = styled.div`
color: ${(props) => (props.activeTab ? 'black' : '#878f97')};
font-weight: ${(props) => (props.activeTab ? 'bold' : 'normal')};
display: inline-block;
margin-right: 20px;
cursor: pointer;
`;
function CategoryTab({ activeTab, setActiveTab }) {
const handleTapBtn = (index) => {
setActiveTab(data[index].category);
};
const data = [
{ category: '전체' },
{ category: '기술·가전' },
{ category: '푸드' },
{ category: '패션' },
{ category: '뷰티' },
// ...
];
return (
<TabBox>
<Ul>
{data.map((item, index) => (
// 스타일드 컴포넌트에서는 $ 기호를 props 앞에 붙혀야 한다.
<Li key={item.category} onClick={() => handleTapBtn(index)} $activeTab={item.category === activeTab}>
{item.category}
</Li>
))}
</Ul>
<Hr />
</TabBox>
);
}
export default CategoryTab;
🌟 발생한 문제
문제
-
초기 CategoryTab 컴포넌트에서 클릭 이벤트 핸들러인 handleTapBtn 함수에서 setActiveTab을 호출할 때, 숫자를 넘겨주었다.
// src/CategoryTab const handleTapBtn = (index) => { setActiveTab(index); };
이유
-
CategoryTab에서 사용된 데이터(data 배열)의 각 요소의 category 값은 문자열인 반면, 제품 데이터(ProductsList.productList)의 각 요소의 category 값이 숫자로 되어있어서 필터가 적용되지 않는 문제가 있었다.
.filter((product) => activeTab === '전체' || activeTab === product.category)
console.log(activeTab); console.log(ProductsList.productList.map((product) => product.category));
해결과정
-
handleTapBtn 함수 내부에서 setActiveTab을 호출할 때, 숫자를 넘기는 것이 아니라 실제 데이터의 category 값(문자열)을 사용하도록 수정하였다.
const handleTapBtn = (index) => { setActiveTab(data[index].category); };
알게된 점
JSON 데이터 필터링
JSON 형식의 데이터를 필터링하여 원하는 조건에 따라 데이터를 추출하는 방법을 알게 되었다.
특히, filter 함수를 활용하여 특정 조건에 맞는 데이터를 선택하는 과정을 이해하게 되었다.
styled-components 에서 $ 기호를 props 앞에 붙혀야한다.
styled-components 라이브러리에서는 $ 기호를 props 앞에 붙임으로써, 해당 props가 실제 DOM 요소에 전달되는 것을 방지할 수 있다.
React와 styled-components가 기본적으로 모든 props을 DOM 요소에게 전달하는 특성 때문이다.
$ 기호를 붙힌 props는 오직 스타일링에만 사용되기 때문에, 해당 props가 실제 DOM 요소에 전달되는 것을 방지할 수 있는 것이다.
즉, 임시적으로 사용되는 prop임을 $를 통해 나타낼 수 있다.
const Li = styled.div`
color: ${(props) => (props.activeTab ? "black" : "#878f97")};
font-weight: ${(props) => (props.activeTab ? "bold" : "normal")};
`;
// 실제 DOM 요소에 전달되는 것을 방지 → 스타일링에만 사용
<Li $activeTab={item.category === activeTab}>{item.category}</Li>
댓글남기기