2 분 소요


아래와 같은 상품 카테고리 필터링을 구현해보자.

✨ 구현 방안

먼저 아래와 같이 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>


태그:

카테고리:

업데이트:

댓글남기기