본문 바로가기

Libraries/React

[React] Filter (3) 리스트 카테고리 필터링

728x90

 

리액트에서 카테고리 필터링 하는 방법을 알아보자!

 

 

 

 만들 예제의 완성본 

 

 

 

 


 

 

 

 파일 구성 

 

App.js : 메인페이지

List.jsx (컴포넌트) : 리스트아이템이 합쳐진 리스트들 

ListItem.jsx (컴포넌트) : 리스트 개별 아이템

Filter.jsx (컴포넌트) : 필터

data.js : 더미데이터

 

 

 

 파일 구조 

 

- App.js에서 List.jsx(리스트들)와 Filter.jsx(필터)를 import한다.

- List.jsx(리스트들)에서는 ListItem.jsx(리스트아이템)를 import한다.

- App.js에서는 data.js(더미데이터)를 import한다. 그리고 이 데이터를  필터해서 List.jsx(리스트들)에게 전달해줄 것이다.

 

 


 

 

 1. 기본 마크업을 한다. 

 

 App.js 

import { Filter } from "./Filter";
import { List } from "./List";
import "./styles.css";
import { data } from "./data.js";

export default function App() {

  return (
    <div className="App">
      <header>
        <h1>머신사</h1>
      </header>

      <Filter />
      <List data={data} /> // 데이터 전달
    </div>
  );
}

 

 

 List.jsx 

import "./List.css";
import { ListItem } from "./ListItem";

export const List = ({ data }) => {
  return (
    <div className="list-container">
      {data.map((it) => {
        return <ListItem key={it.id} {...it} />;
      })}
    </div>
  );
};

 

 

 ListItem.jsx 

import "./ListItem.css";

export const ListItem = (props) => {
  return (
    <div>
      <div className="list-item-container">{props.title}</div>
    </div>
  );
};

 

 

 Filter.jsx 

export const Filter = () => {
  return (
    <div>
      <div className="filter-container">
        <button type="button" className="all"> 전체 </button>
        <p className="filter-bar"> | </p>
        <button type="button" className="top"> 상의 </button>
        <p className="filter-bar"> | </p>
        <button type="button" className="bottom"> 하의 </button>
        <p className="filter-bar"> | </p>
        <button type="button" className="outer"> 아우터 </button>
      </div>
    </div>
  );
};

 

 

 data.js 

export const data = [
  {
    id: 1,
    category: "top",
    title: "상의1",
  },
  {
    id: 2,
    category: "top",
    title: "상의2",
  },
  {
    id: 3,
    category: "top",
    title: "상의3",
  },
  {
    id: 4,
    category: "bottom",
    title: "하의1",
  },
  {
    id: 5,
    category: "bottom",
    title: "하의2",
  },

  {
    id: 6,
    category: "bottom",
    title: "하의3",
  },
  {
    id: 7,
    category: "outer",
    title: "아우터1",
  },
  {
    id: 8,
    category: "outer",
    title: "아우터2",
  },
  {
    id: 9,
    category: "outer",
    title: "아우터3",
  },
];

 

 

 

기본적 마크업을 끝내면, 아래와 같이 화면에 뜬다.

 

 

 

 

 2. App.js에서 선택된 카테고리 필터의 state를 설정하고, state를 props로 Filter 컴포넌트에 전달해준다. 

 

 App.js 

import { Filter } from "./Filter";
import { List } from "./List";
import "./styles.css";
import { data } from "./data.js";
import { useState } from "react";

export default function App() {

  const [selectedCategory, setSelectedCategory] = useState("all"); // state의 기본값은 전체보기(all)

  return (
    <div className="App">
      <header>
        <h1>머신사</h1>
      </header>

      <Filter
        setSelectedCategory={setSelectedCategory} // setState 전달
        selectedCategory={selectedCategory} // state 전달
      />
      <List data={data} />
    </div>
  );
}

 

 

 

 3. Filter.jsx에서 props로 state를 전달 받고, onClick 이벤트에 setState를 달아서, 특정 카테고리를 클릭하면 해당 카테고리로 상태를 바뀌게끔 설정해준다. 

 

 Filter.jsx 

import "./Filter.css";

export const Filter = ({setSelectedCategory, selectedCategory}) => {
  return (
    <div>
      <div className="filter-container">
        <button
          type="button"
          className="all"
          onClick={() => setSelectedCategory("all")}
        >
          전체
        </button>
        <p className="filter-bar"> | </p>
        <button
          type="button"
          className="top"
          onClick={() => setSelectedCategory("top")}
        >
          상의
        </button>
        <p className="filter-bar"> | </p>
        <button
          type="button"
          className="bottom"
          onClick={() => setSelectedCategory("bottom")}
        >
          하의
        </button>
        <p className="filter-bar"> | </p>
        <button
          type="button"
          className="outer"
          onClick={() => setSelectedCategory("outer")}
        >
          아우터
        </button>
      </div>
    </div>
  );
};

 

 

 

 4. App.js에서 데이터의 카테고리가 (선택된 카테고리인) state인 것들(=selectedCategory)로 필터하고, 
 List.jsx 컴포넌트에 filter한 데이터(filteredList)를 props로 넘겨준다. 

 

 App.js 

import { Filter } from "./Filter";
import { List } from "./List";
import "./styles.css";
import { data } from "./data.js";
import { useState } from "react";

export default function App() {
  const [selectedCategory, setSelectedCategory] = useState("all");


// state가 "all"이면 data 전체를 넘겨주고, 그게 아니면 선택된 category에 해당하는 데이터만 filter해서 넘겨준다.
  const filteredList =
    selectedCategory === "all"
      ? data
      : data.filter((item) => item.category === selectedCategory);

  return (
    <div className="App">
      <header>
        <h1>머신사</h1>
      </header>

      <Filter
        setSelectedCategory={setSelectedCategory}
        selectedCategory={selectedCategory}
      />
      <List filteredList={filteredList} /> // filteredList를 props로 넘겨줌
    </div>
  );
}

 

 



 5. List.jsx에서 필터한 데이터 (filteredList)를 props로 받고 map을 돌린다. 

 

 List.jsx 

import "./List.css";
import { ListItem } from "./ListItem";

export const List = ({ filteredList }) => {
  return (
    <div className="list-container">
      {filteredList.map((it) => {
        return <ListItem key={it.id} {...it} />;
      })}
    </div>
  );
};

 

 

필터 기능이 완성 되었다.

 

 

 

 

 6. 해당 필터를 선택했을때 "글자파란색+밑줄" CSS가 유지되게하기 
삼항연산자를 사용하여 state에 따라 className이 바뀌게 한다. 

 

 Filter.jsx 

import "./Filter.css";

export const Filter = ({ selectedCategory, setSelectedCategory }) => {
  return (
    <div>
      <div className="filter-container">
        <button
          type="button"
          onClick={() => setSelectedCategory("all")}
          className={`${"all"} ${
            selectedCategory === "all" ? "filter-active" : ""
          }`}
        >
          전체
        </button>
        <p className="filter-bar"> | </p>
        <button
          type="button"
          onClick={() => setSelectedCategory("top")}
          className={`${"top"} ${
            selectedCategory === "top" ? "filter-active" : ""
          }`}
        >
          상의
        </button>
        <p className="filter-bar"> | </p>
        <button
          type="button"
          onClick={() => setSelectedCategory("bottom")}
          className={`${"bottom"} ${
            selectedCategory === "bottom" ? "filter-active" : ""
          }`}
        >
          하의
        </button>
        <p className="filter-bar"> | </p>
        <button
          type="button"
          className="outer"
          onClick={() => setSelectedCategory("outer")}
          className={`${"outer"} ${
            selectedCategory === "outer" ? "filter-active" : ""
          }`}
        >
          아우터
        </button>
      </div>
    </div>
  );
};

 

 

 Filter.css 

.filter-container {
  background: white;
  color: black;
  display: flex;
  gap: 10px;
  width: 240px;
  height: 45px;
  margin-top: 20px;
  text-align: center;
  justify-content: center;
}

.filter-container button:hover {
  color: blue;
  text-decoration: underline;
  cursor: pointer;
  font-weight: 600;
}

.all,
.top,
.bottom,
.outer {
  all: unset;
}

.filter-bar {
  margin-top: 10px;
}

.filter-active {
  all: unset;
  font-weight: 600;
  color: blue;
  text-decoration: underline;
}

 

 

전체를 클릭했을 때 className이 바뀐다.

 

 

 

 

 완성본 

 

 

728x90