[React] Checkbox (1) — Context API로 Checkbox 상태 관리하기
프로젝트를 하면서 카테고리를 체크박스로 선택하고 버튼으로 해제하는 기능을 구현해야 했는데
버튼으로 체크박스를 해제하는 방식에서 고민을 많이 해, 포스팅으로 남겨 두려고 합니다.
임의의 배열 데이터로 체크박스를 만들고 Context API로 상태 관리하기
아래와 같은 데이터로 체크박스를 만들었습니다~
// utils/sampleData.js
export const data = [
"가을",
"가람",
"기쁨",
"구름",
"나리",
"너울",
"누리",
"노을",
"눈꽃",
"다솜",
"마음",
"마루",
"미르",
"무늬",
"맑음",
"믿음",
"뭇별",
"바다",
"방울",
"보름",
"봄꽃",
"별빛",
"별밤",
"별숲",
"사랑",
"솔잎",
"새벽",
"새싹",
"샛별",
"아침",
"아름",
"여름",
"이슬",
"여울",
"웃음",
"으뜸",
"열매",
"윤슬",
"저녁",
"잔별",
"초롱",
"풀잎",
"하루",
"하나",
"하늘",
"햇살",
"햇볕",
"햇봄",
];
CategoryContext 만들기
import { createContext } from "react";
const CategoryContext = createContext();
createContext()
로 CategoryContext를 만듭니다.
import { data } from "utils/sampleData";
const CategoryProvider = ({ children }) => {
const categories = [...data];
const categoriesBool = [...Array(categories.length).fill(false)];
let result = {};
categories.forEach((cate, i) => {
result[cate] = categoriesBool[i];
});
const [cateObject, setCateObject] = useState(result);
};
// result = {
// 가을: false,
// 가람: false,
// 기쁨: false,
// 구름: false,
// };
// 같은 객체를 만듭니다
CategoryProvider 안에 key
는 배열이고 value
는 true/false인 객체를 만듭니다.
- import한 배열을 categories에 복사한다.
- 배열 개수만큼의 false로 이루어진 배열을 만든다.
- forEach문으로 빈 배열에 key는 categories 배열, value는 categoriesBool로 구성되도록 객체를 만들어 준다.
- useState로 cateObject를 만들고 초깃값으로 방금 만든 result 배열을 할당한다.
const CategoryProvider = ({ children }) => {
// 생략
return (
<CategoryContext.Provider
value={{
cateObject,
setCateObject,
}}
>
{children}
</CategoryContext.Provider>
);
};
export { CategoryContext, CategoryProvider };
CategoryContext에 Provider
를 이용해 cateObject
와 setCateObject
를 전달해 주고 CategoryContext
, CategoryProvider
를 export합니다.
전체 코드는 다음과 같습니다.
// store/category/index.js
import { createContext, useState } from "react";
import { data } from "utils/sampleData";
const CategoryContext = createContext();
const CategoryProvider = ({ children }) => {
const categories = [...data];
const categoriesBool = [...Array(categories.length).fill(false)];
let result = {};
categories.forEach((cate, i) => {
result[cate] = categoriesBool[i];
});
const [cateObject, setCateObject] = useState(result);
return (
<CategoryContext.Provider
value={{
cateObject,
setCateObject,
}}
>
{children}
</CategoryContext.Provider>
);
};
export { CategoryContext, CategoryProvider };
CheckboxList 컴포넌트 만들기
checkbox가 여러 개 담길 CheckboxList를 만들어 보겠습니다.
// CheckboxList.jsx
import React, { useContext } from "react";
import Checkbox from "./Checkbox";
import { CategoryContext } from "store/category";
const CheckboxList = () => {
const { cateObject } = useContext(CategoryContext);
return (
<div>
{Object.keys(cateObject).map((key, i) => {
return (
<div key={i}>
<Checkbox value={key} checked={cateObject[key]} />
{key}
</div>
);
})}
</div>
);
};
export default CheckboxList;
cateObject
의 키 값을 사용해 체크박스를 만들 것이므로 useContext
를 사용해 cateObject
를 불러옵니다.
Array.map()을 이용할 건데, 현재 cateObject는 Object이므로 map을 사용할 수 없습니다.
Object.keys()를 이용하면 Object의 key 값만 배열로 반환해 줍니다.
밑에서 만들 Checkbox 컴포넌트에 value와 checked를 전달해 줍니다.
value는 키값이 될 것이고, checked
는 cateObject의 key가 가지고 있는 값, 즉 value인 true / false 값이 될 것입니다.
Checkbox 컴포넌트 만들기
import { useContext } from "react";
import { CategoryContext } from "store/category";
const { cateObject, setCateObject } = useContext(CategoryContext);
useContext에 CategoryContext를 전달해 Provider에 넣어 줬던 cateObject와 setCateObject를 받아옵니다.
const Checkbox = ({ value, checked }) => {
const checkHandler = () => {
let copyObject = { ...cateObject };
copyObject[value] = !checked;
setCateObject(copyObject);
}
return (
<div>
<input
type="checkbox"
checked={checked}
value={value}
onChange={checkHandler}
/>
</div>
);
};
CheckboxList에서 value와 checked를 전달해 줬으므로 props로 받아옵니다.
체크박스 타입의 input을 리턴해 주고,
체크박스가 체크되었는지 나타내는 checked
속성에는 checked
를, 체크 박스 옆에 출력할 값(value)에 value를 전달해 줍니다.
체크박스가 선택될 때마다 실행될 onChange 이벤트 핸들러에는 checkHandler를 전달합니다.
const checkHandler = () => {
let copyObject = { ...cateObject };
copyObject[value] = !checked;
setCateObject(copyObject);
};
checkbox의 onChange에 전달할 checkHandler
함수를 만듭니다.
cateObject
의 복사본으로 copyObject
를 만들고, copyObject의 key 값에 접근해 checked 상태를 현 상태와 반대로 만듭니다.
만약 ◻️가을
의 체크박스를 ☑️가을
로 만들었다면 checkHandler의 value는 가을이 될 것이고, false였던 상태가 true로 바뀌어 copyObject의 {"가을": false}
는 {"가을": true}
로 바뀔 것입니다.
상태를 바꿔 준 copyObject
는 setCateObject
의 인자로 전달해 cateObject
를 copyObject
로 만들어줍니다.
전체 코드는 다음과 같습니다.
// Checkbox.jsx
import { useContext } from "react";
import { CategoryContext } from "store/category";
const Checkbox = ({ value, checked }) => {
const { cateObject, setCateObject } = useContext(CategoryContext);
const checkHandler = () => {
let copyObject = { ...cateObject };
copyObject[value] = !checked;
setCateObject(copyObject);
}
return (
<div>
<input
type="checkbox"
checked={checked}
value={value}
onChange={checkHandler}
/>
</div>
);
};
export default Checkbox;
이제 CheckboxList.jsx를 App.js에서 렌더링하면 첨부 사진과 같이 data로부터 체크박스가 렌더링된 것을 확인할 수 있습니다.
콘솔창에도 value와 cateObject[value]가 제대로 출력됩니다.
배열로도 더 간편하게 상태 관리를 할 수 있으니 참고해 주시길 바랍니다.
도움이 되셨다면 저에게 힘이 되는 공감 버튼이나 댓글 부탁드려요. (--)(__)