일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 그리디
- 서버 컴포넌트
- 날씨 api
- 백준
- 카테고리필터
- 동전 0
- react
- 배열 메소드
- 숫자를 별점으로
- 중복선택
- 자바스크립트
- 항해99추천
- db수정
- JavaScript
- jQuery
- 클라이언트 컴포넌트
- 실전프로젝트
- server component
- NextJS v13
- 로딩 후 실행
- 탐욕알고리즘
- 배열 중복 제거
- greedy
- 항해99
- 중복카테고리
- 항해99후기
- 프로그래머스
- 항해99솔직후기
- 부트캠프항해
- 알고리즘
- Today
- Total
공부 및 일상기록
[React] 중복 선택 가능한 카테고리 필터 만들기 본문
Side프로젝트로 진행하는 방탈출 관련 웹페이지를 만들고 있다.
오늘은 방탈출 테마들을 여러가지 카테고리를 받아서 해당하는 테마만 필터링 하는 기능을 만들었다.
아직 백엔드쪽에서 서버도 구현되지 않고 API 명세서도 확실하지 않아서 기능만 구현된 상태다.
여기서 한가지만 선택한다면 쉽게 구현되었겠지만 나는 중복 선택을 가능하도록 만들어야 했다.
버튼컴포넌트
먼저 저 버튼들을 만들어줄 컴포넌트를 만들었다.
//버튼 컴포넌트
import { useEffect } from "react";
import styled from "styled-components";
const CategoryBtn = ({ categoryIndex, state, setState }) => {
useEffect(() => {
if (state.length === 0) {
setState(["전체"]);
}
}, [state]);
const categoryHandler = (e) => {
console.log(isNaN(e.target.value));
//해당 State에 클릭한 카테고리가 있는지 확인한다. (있다면 클릭한 카테고리를 반환하고, 없다면 undefinded가 됨)
const isInclude = state.find((element) => element === e.target.value);
console.log("isInclude", isInclude);
//만약 클릭한 카테고리가 "전체" 인 경우 state는 "전체" 로 바꾼다.
if (e.target.value === "전체") {
setState(["전체"]);
//만약 isInclude가 값이 있다면 (클릭해제를 하려는것과 같은 의미), state에서 클릭한 카테고리만 제외시킴
} else if (isInclude) {
setState(state.filter((element) => element !== e.target.value));
// state에 "전체"가 있다면 "전체"를 state에서 빼내고 나머지 클릭한 값들을 넣어줌
} else {
setState([
...state.filter((element) => element !== "전체"),
e.target.value,
]);
}
};
return (
<>
{categoryIndex.map((element) => (
<Btn
key={element.name}
type="button"
onClick={categoryHandler}
value={element.value}
backgroundColor={state.find((el) => el === `${element.value}`)}
>
{element.name}
</Btn>
))}
</>
);
};
export default CategoryBtn;
const Btn = styled.button`
margin: 3px;
font-size: 12px;
color: ${({ backgroundColor }) => (backgroundColor ? "white" : "black")};
background-color: ${({ backgroundColor }) =>
backgroundColor ? "#428bca" : "#fff"};
border: 1px solid #e5e5e5;
border-radius: 4px;
outline: none;
cursor: pointer;
&:hover {
color: #333;
color: ${({ backgroundColor }) => (backgroundColor ? "white" : "black")};
background-color: ${({ backgroundColor }) =>
backgroundColor ? "#428bca" : "#e6e6e6"};
border-color: #adadad;
}
`;
나는 여러가지 카테고리 목록 (categoryIndex)과 해당 목록별 state들을 부모컴포넌트에서 관리하려고 props로 받아서 만드는 방법을 선택했다.
**여기서 Btn 컴포넌트에 backgroundColor 프롭스에 왜 백틱을 걸었는지에 대해 짧게 설명하면 setState를 할 때, event.target.value 처럼 온체인지or온클릭 으로 받아온 값들을 넣으면 숫자형이 문자형으로 바뀌는 문제가 있어서 백틱을 걸어서 해당 부분을 숫자가 아닌 문자로 비교하여 비교가 잘 되도록 한것입니다.
부모컴포넌트
그럼 부모컴포넌트는 어떻게 생겼는지 확인해보자.
//버튼의 부모 컴포넌트
import { useState } from "react";
import styled from "styled-components";
//CategoryIndex들이 모여있는 카테고리컴포넌트도 import한다.
import Category from "./Category";
import CategoryBtn from "./CategoryBtn";
const ThemeFilter = () => {
const [genre, setGenre] = useState(["전체"]);
const [location, setLocation] = useState(["전체"]);
const [score, setScore] = useState(["전체"]);
const [difficulty, setDifficuldy] = useState(["전체"]);
const [people, setPeople] = useState(["전체"]);
return (
<Container>
<FilterWrap>
<p>지역별</p>
<CategoryBtn
categoryIndex={Category.LocationCategory}
state={location}
setState={setLocation}
/>
<p>장르</p>
<CategoryBtn
categoryIndex={Category.GenreCategory}
state={genre}
setState={setGenre}
/>
<p>평점</p>
<CategoryBtn
categoryIndex={Category.ScoreCategory}
state={score}
setState={setScore}
/>
<p>난이도</p>
<CategoryBtn
categoryIndex={Category.DifficultyCategory}
state={difficulty}
setState={setDifficuldy}
/>
<p>예약 가능 인원</p>
<CategoryBtn
categoryIndex={Category.PeopleCategory}
state={people}
setState={setPeople}
/>
</FilterWrap>
</Container>
);
};
export default ThemeFilter;
const Container = styled.div`
height: 370px;
width: 100%;
display: flex;
justify-content: center;
/* align-items: center; */
background-color: #eee6c4;
`;
const FilterWrap = styled.div`
height: 100%;
width: 90%;
/* cursor: pointer; */
border: 1px solid red;
`;
각 카테고리 state들을 만들어 두고 return에서 버튼 컴포넌트를 불러와서 props로 해당 카테고리와 state, setState들을 넘겨주었다.
카테고리
CategoryIndex는 딱히 보고싶은사람은 없겠지만 혹시 저처럼 코드초보인 경우에 자료가 없으면 이해하지 못하시는 분이 계실수도 있기에 첨부하겠습니다.
//각 카테고리를 정리해둔 카테고리컴포넌트
const Category = {
GenreCategory: [
{
name: "전체",
value: "전체",
},
{
name: "SF/판타지",
value: "SF/판타지",
},
{
name: "코믹",
value: "코믹",
},
{
name: "추리",
value: "추리",
},
{
name: "잠입/범죄",
value: "잠입/범죄",
},
{
name: "어드벤처/모험",
value: "어드벤처/모험",
},
{
name: "스릴러",
value: "스릴러",
},
{
name: "공포",
value: "공포",
},
{
name: "19금",
value: "19금",
},
{
name: "미스테리",
value: "미스테리",
},
{
name: "미션",
value: "미션",
},
{
name: "로맨스",
value: "로맨스",
},
{
name: "드라마/감성",
value: "드라마/감성",
},
{
name: "동화",
value: "동화",
},
],
LocationCategory: [
{
name: "전체",
value: "전체",
},
{
name: "강남",
value: "강남",
},
{
name: "홍대",
value: "홍대",
},
{
name: "건대",
value: "건대",
},
{
name: "신촌",
value: "신촌",
},
{
name: "대학로",
value: "대학로",
},
{
name: "강북",
value: "강북",
},
{
name: "신림",
value: "신림",
},
{
name: "서울(기타)",
value: "서울(기타)",
},
],
ScoreCategory: [
{
name: "전체",
value: "전체",
},
{
name: "⭐️",
value: 1,
},
{
name: "⭐️⭐️",
value: 2,
},
{
name: "⭐️⭐️⭐️",
value: 3,
},
{
name: "⭐️⭐️⭐️⭐️",
value: 4,
},
{
name: "⭐️⭐️⭐️⭐️⭐️",
value: 5,
},
],
DifficultyCategory: [
{
name: "전체",
value: "전체",
},
{
name: "🔒",
value: 1,
},
{
name: "🔒🔒",
value: 2,
},
{
name: "🔒🔒🔒",
value: 3,
},
{
name: "🔒🔒🔒🔒",
value: 4,
},
{
name: "🔒🔒🔒🔒🔒",
value: 5,
},
],
PeopleCategory: [
{
name: "전체",
value: "전체",
},
{
name: "1인",
value: 1,
},
{
name: "2인",
value: 2,
},
{
name: "3인",
value: 3,
},
{
name: "4인",
value: 4,
},
{
name: "5인",
value: 5,
},
],
};
export default Category;
해당 카테고리용 버튼컴포넌트는 재사용성이 있다고 판단되어 따로 빼서 사용하였고 카테고리들도 단순하지만 너무 긴 정보들을 담고있는것 같아 따로 빼서 사용하였다.
'개발 > React' 카테고리의 다른 글
[React] 페이지네이션 구현하기 (라이브러리 : react-js-pagination) (0) | 2022.12.15 |
---|---|
[React] 리액트 경로 이동시 스크롤 상단 이동 방법 (0) | 2022.12.14 |
[React] useState 한 박자 느리게 찍히는 문제 (비동기) (0) | 2022.10.30 |
[React] 새로고침 시에도 리덕스 내부의 데이터를 유지하는 방법 (0) | 2022.10.13 |
[React] form 내부의 submit 사용시 리덕스 데이터 초기화 원인 (0) | 2022.10.13 |