체크박스를 이용한 카테고리 검색 기능은 팀 프로젝트의 핵심 기능이였다.
가. 각각의 카테고리를 클릭하면 각 카테고리를 태그로 입력한 글들을 보여주는 기능
나. 다른 카테고리를 클릭하면 기존의 선택된 카테고리가 사라지는 기능
다. 다른 카테고리를 클릭하면 추가로 카테고리가 선택되는 기능
const menuData = [
{ key: "0", value: "비건", checked: false, index: 0 },
{ key: "1", value: "아시안푸드", checked: false, index: 1 },
{ key: "2", value: "양식", checked: false, index: 2 },
{ key: "3", value: "일식", checked: false, index: 3 },
{ key: "4", value: "중식", checked: false, index: 4 },
{ key: "5", value: "한식", checked: false, index: 5 },
{ key: "6", value: "할랄", checked: false, index: 6 },
];
가) menuData
라는 변수에 카테고리의 데이터를 만들어서 할당을 해준다.
나) key
의 경우 map
의 key
값을 위해 사용
다) value
는 각각의 카테고리 값
라) checked
는 CSS와 카테고리가 check
된 상태인지 확인하기 위해서 사용
마) index
는 의미가 없었네,,,
const onChangeMenu = (checked: any, item: any) => {
if (checked) {
props.setMenuTagCheckList([item]);
props.setMenuHashTag([item]);
} else if (!checked) {
props.setMenuHashTag(props.menuHashTag.filter((el) => el !== item));
props.setMenuTagCheckList(
props.menuTagCheckList.filter((el) => el !== item)
);
}
};
가) onChangeMenu
라는 함수를 생성하고 인자로 checked
와 item
을 받아준다.
checked
는 menuData
의 checked
값이고 item
은 menuData
의 value
값이다.
나) menuHashTag
, setMenuHashTag
, menuTagCheckList
, setMenuTagCheckList
는 상위 컴포넌트에서 받아온 state이다
menuHashTag
, setMenuHashTag
는 선택한 태그를 관리하는 state이다
menuTagCheckList
, setMenuTagCheckList
는 선택한 태그가 체크 되었는지 관리하는 state인데 지금보니 필요가 없다.
다) onChangeMenu
함수의 인자값인 item
이 checked
상태(선택)가 true가 되고 item의 상태가 true가 되면 menuHashTag
배열에 추가 된다.
라) 만약 다시 클릭을 하면 checked
의 상태가 false
가 되고 menuHashTag
에서 빠진다.
props.setMenuHashTag(props.menuHashTag.filter((el) => el !== item));
menuHashTag
의 배열에서 filter
함수를 이용해서 기존에 들어있는 item과 같지 않은 것들만 menuHashTag
에 남게 된다.
즉 똑같은 item을 클릭하면 기존의 item은 제외가 되는 것이다.
{menuData.map((el) => (
<label className="checkbox" key={el.key}>
<input
type="checkbox"
value={el.value}
onChange={(e) => {
onChangeMenu(e.target.checked, e.target.value);
}}
checked={props.menuTagCheckList.includes(el.value)}
/>
<span className="checkbox_text">{el.value}</span>
</label>
))}
가) menuData
를 map
함수를 이용해서 만들어 카테고리를 생성한다.
나) input
을 checkbox
로 만들어 주고 value
값은 menuData
의 value
값으로 설정해둔다.
다) onChange
함수에 event(e)를 주고 위에서 만든 onChangeMenu
를 바인딩 해주고 event의 target
에 있는 checked
와 value
값을 인자로 넘겨준다.
라) checked
상태를 menuTagCheckList
를 줬는데 menuHashTag
로 줘도 상관이 없다. menuHashTag
에 있는 값(item)이 includes
를 이용해 menuData
의 값과 일치하는 지 확인한다. 즉 일치하면 checked
상태가 true가 되는 것이다.
마) 체크박스의 값을 menuData
의 value
값으로 설정한다.
export const OpenTag = styled.div`
display: flex;
flex-wrap: wrap;
font-weight: 700;
font-size: 16px;
.checkbox input {
display: none;
}
.checkbox {
display: flex;
margin: 0px 30px 10px 0px;
@media ${breakPoints.mobile} {
margin: 0 6px 8px 0;
}
}
.checkbox_text {
display: flex;
background-color: #d2d2d2;
margin-left: 10px;
font-size: 16px;
color: #ffffff;
padding: 7px 20px;
border-radius: 50px;
cursor: pointer;
&:hover {
background-color: #ff9a31;
color: #ffffff;
}
}
.checkbox input:checked + .checkbox_text {
color: #ffffff;
background-color: #ffa230;
}
`;
미디어 부분은 제외했다.
가) 기존의 CSS를 제외하고 선택된 상태에서 CSS만 보면
.checkbox input:checked + .checkbox_text {
color: #ffffff;
background-color: #ffa230;
}
input
이 checked
가 되고 checkbox_text
이라는 className
을 가진 태그를 color
와 background-color
를 변경해준다.
가
와 동일하나 함수부분이 상이함const onChangeMood = (checked, item) => {
if (checked) {
props.setMoodHashTag([...props.moodHashTag, item]);
} else if (!checked) {
props.setMoodHashTag(props.moodHashTag.filter((el) => el !== item));
}
};
가) setMoodHashTag
에서 가
에서는 기존의 item 하나만 들어갔으나 스프레드 연산자를 이용해서 기존의 아이템에 새로 선택된 아이템을 추가해준다.
...props.moodHashTag
나) 역시 filter를 이용해서 같은 것이 선택되면 배열에서 제외되도록 해준다.
다) CSS역시 동일하다
export default function MenuFilterPage(props: any) {
const menuData = [
{ key: "0", value: "비건", checked: false, index: 0 },
{ key: "1", value: "아시안푸드", checked: false, index: 1 },
{ key: "2", value: "양식", checked: false, index: 2 },
{ key: "3", value: "일식", checked: false, index: 3 },
{ key: "4", value: "중식", checked: false, index: 4 },
{ key: "5", value: "한식", checked: false, index: 5 },
{ key: "6", value: "할랄", checked: false, index: 6 },
];
const onChangeMenu = (checked: any, item: any) => {
if (checked) {
props.setMenuTagCheckList([item]);
props.setMenuHashTag([item]);
} else if (!checked) {
props.setMenuHashTag(props.menuHashTag.filter((el: any) => el !== item));
props.setMenuTagCheckList(
props.menuTagCheckList.filter((el: any) => el !== item)
);
}
};
return (
<S.OpenTag>
{menuData.map((el) => (
<label className="checkbox" key={el.key}>
<input
type="checkbox"
value={el.value}
onChange={(e) => {
onChangeMenu(e.target.checked, e.target.value);
}}
checked={props.menuTagCheckList.includes(el.value)}
/>
<span className="checkbox_text">{el.value}</span>
</label>
))}
</S.OpenTag>
);
}
export default function MoodFilterPage(props: any) {
const moodData = [
{ key: "0", value: "가족들과", checked: false, index: 0 },
{ key: "1", value: "동창회자리로좋은", checked: false, index: 0 },
{ key: "2", value: "부모님과함께", checked: false, index: 0 },
{ key: "3", value: "소개팅", checked: false, index: 0 },
{ key: "4", value: "술자리로좋은", checked: false, index: 0 },
{ key: "5", value: "썸타는사람과", checked: false, index: 0 },
{ key: "6", value: "애인과함께", checked: false, index: 0 },
{ key: "7", value: "친구와함께", checked: false, index: 0 },
{ key: "8", value: "혼밥하기좋은", checked: false, index: 0 },
{ key: "9", value: "혼술하기좋은", checked: false, index: 0 },
{ key: "10", value: "회식자리로좋은", checked: false, index: 0 },
];
const onChangeMood = (checked: any, item: any) => {
if (checked) {
props.setMoodHashTag([...props.moodHashTag, item]);
} else if (!checked) {
props.setMoodHashTag(props.moodHashTag.filter((el: any) => el !== item));
}
};
return (
<S.OpenTag>
{moodData.map((el) => (
<label className="checkbox" key={el.key}>
<input
type="checkbox"
value={el.value}
onChange={(e) => {
onChangeMood(e.target.checked, e.target.value);
}}
checked={props.moodHashTag.includes(el.value)}
/>
<span className="checkbox_text">
<img className="check_icon" src="/images/check.png" />
{el.value}
</span>
</label>
))}
</S.OpenTag>
);
}
체크를 구현하였기 때문에 체크가 진짜 잘 되었는지 확인할 필요가 있다.
가. 고차함수 이용하기
const onChangeCheckMenu = (el: any) => (event: any) => {
const select = menuTagData.map((el, idx) => {
return { ...el, checked: idx === Number(event.target.id) };
});
setMenuTagData(select);
setBoardTagMenu(el.value);
};
container부분
{props.menuTagData.map((el: any, idx: any) => (
<label className="checkbox" key={el.key}>
<input
type="checkbox"
id={String(idx)}
onChange={props.onChangeCheckMenu(el)}
checked={Boolean(el.checked)}
/>
<span className="checkbox_text">{el.value}</span>
</label>
))}
presenter 부분
presenter부분에서 map을 돌린 이후 데이터들을 onChangeCheckMenu의 인자로 넣어준다.
이후에
onChangeCheckMenu는 el을 인자값으로 받아오는 HOF으로 만들어 준다.
이때 두번째 인자값으로는 event를 넣어준다.
select라는 변수를 만들어 주고 여기에 메뉴태그데이터를 map함수를 이용해서 클릭해서 해당 menuData의 checked값을 true 변경하도록 하는데 이때 다시 클릭이 되었을 경우에 id값을 확인하여 다를 경우 두번째 선택된 데이터의 checked를 true로 같을 경우는 기존의 것을 true로 하라고 만들어 준다.
이후 select를 setMenuTagData에 넣어주면 ...el로 인해 변경된 값만 true로 변경된다.
setBoardTagMenu에는 el.value가 들어가게 된다.
presenter부분에서 input의 checked에는 el.checked가 들어가 있기 때문에 태그 데이터에서 checked된 것만 배열로 들어갈 수 있다.