TECH

[React] Checkbox (1) — Context API로 Checkbox 상태 관리하기

ttaerrim 2022. 2. 19. 20:00

 

 

프로젝트를 하면서 카테고리를 체크박스로 선택하고 버튼으로 해제하는 기능을 구현해야 했는데

버튼으로 체크박스를 해제하는 방식에서 고민을 많이 해, 포스팅으로 남겨 두려고 합니다.

 

 

임의의 배열 데이터로 체크박스를 만들고 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인 객체를 만듭니다.

  1. import한 배열을 categories에 복사한다.
  2. 배열 개수만큼의 false로 이루어진 배열을 만든다.
  3. forEach문으로 빈 배열에 key는 categories 배열, value는 categoriesBool로 구성되도록 객체를 만들어 준다.
  4. useState로 cateObject를 만들고 초깃값으로 방금 만든 result 배열을 할당한다.

 

const CategoryProvider = ({ children }) => {

  // 생략

  return (
    <CategoryContext.Provider
      value={{
        cateObject,
        setCateObject,
      }}
    >
      {children}
    </CategoryContext.Provider>
  );
};

export { CategoryContext, CategoryProvider };

CategoryContext에 Provider를 이용해 cateObjectsetCateObject를 전달해 주고 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}로 바뀔 것입니다.

상태를 바꿔 준 copyObjectsetCateObject의 인자로 전달해 cateObjectcopyObject로 만들어줍니다.

 

 

전체 코드는 다음과 같습니다.

// 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]가 제대로 출력됩니다.

 

 

 

 

 

배열로도 더 간편하게 상태 관리를 할 수 있으니 참고해 주시길 바랍니다.

 

 

 

도움이 되셨다면 저에게 힘이 되는 공감 버튼이나 댓글 부탁드려요. (--)(__)