Recent Posts
Recent Comments
«   2024/07   »
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 29 30 31
Today
Total
관리 메뉴

DH의 개발 공부로그

[React] 리액트 Checkbox 문제 해결하기! - 전체 선택/해제 기능 본문

React

[React] 리액트 Checkbox 문제 해결하기! - 전체 선택/해제 기능

DeveloperDH 2023. 3. 20. 20:03
728x90

문제 발견

이전의 작업을 했던 리액트 Set을 이용한 checkbox를 다루었던 코드에서 문제점이 있었습니다.
[React] 리액트에서 Set 이용한 Checkbox 상태관리하기!
이전의 코드를 확인하고 싶으면 다음과 같습니다. 이전 소스코드 확인하기

문제점이 무엇인지 확인을 해보면, 우선 전체선택과 개별선택이 있는

체크박스의 기능들은 다음과 같아야 합니다.

  1. 개별 체크박스 선택/해제 기능
  2. 전체 선택을 클릭 시 전체 선택/해제 변경 기능
  3. 전체 선택 시에 하나라도 체크가 해제되면 전체 선택 박스 체크 해제
  4. 모든 체크박스가 선택될 경우 전체 선택 박스 체크 활성화

이렇게 4가지의 경우가 충족이 되어야 합니다.
하지만 위의 코드에서 1번과 2번의 조건은 충족이 되지만, 3번과 4번의 기능들은 충족하지 못하는 문제가 있었습니다.
그렇기 때문에 다음과 같이 코드를 수정했습니다.

코드 수정

수정 된 코드 확인하기

1. 배열을 이용

Set을 이용하는 방법도 좋은 방법이라고 생각은 하지만,
코드를 더욱 줄이고, 배열을 이용하여 특별한 메서드 없이 쉽게 다룰 수 있다고 판단하여 배열로 변경을 하였습니다.

const [checkItems, setCheckItems] = useState([])

2. 코드 단축 - checkItemHandler(), allCheckedHandler()

Set을 이용했을 때는 Set의 메서드를 이용해서 추가 또는 삭제 후 다시 setCheckItems에 넣어주는 형태 였다면,
배열을 이용해서 간편하고 단순하게 다음과 같이 작업을 했습니다.

const checkItemHandler = (id, isChecked) => {
  if (isChecked) {
    setCheckItems((prev) => [...prev, id]) // 불변성을 지키기 위한 원본 배열을 복사 후 추가
  } else {
    setCheckItems(checkItems.filter((item) => item !== id)) 
    // 현재 checkItems의 배열에서 해당 id를 제외한 새로운 배열 반환
  }
}

 

기존 코드에서는 CheckBoxList, CheckBox 컴포넌트 양쪽에서 allCheckedHandler()를 만들어
작업을 하면서 같은 이름의 함수로 인한 가독성을 헤치는 작업을 했던 부분을 제거 하고,
CheckBoxList에 다음과 같은 코드로 단축을 했습니다.

const allCheckedHandler = (e) => {
  if (e.target.checked) { 
    setCheckItems(checkList.map((item) => item.id))
  } else {
    setCheckItems([]);
  }
  console.log(`allCheck = `, e.target.checked)
}

3. 개별 선택 해제 시 전체 선택 해제

이 부분이 가장 중요하다고 생각이 됩니다.
이 기능 때문에 코드를 수정을 했기 때문입니다.
코드는 다음과 같이 수정을 했습니다.

// CheckBoxList.jsx
<header>
  <label>
  <input type="checkbox" onChange={allCheckedHandler} 
    checked={checkItems.length === checkList.length ? true : false}/>
  전체선택
  </label>
</header>
<div>
  {
    checkList.map((item) => (
      <CheckBox key={item.id} id={item.id} checkItemHandler={checkItemHandler}
    checked={checkItems.includes(item.id) ? true : false} />
    ))
  }
</div>

원래는 checkeduseState를 이용해서 상태를 관리했는데 삼항연산자로 수정을 하면서 문제를 해결을 했습니다.

checked={checkItems.length === checkList.length ? true : false}
// checkItems, 체크된 아이템의 개수와 현재 데이터 개수가 다를 경우 선택 해제 (하나라도 해제 시 선택 해제)
 {
  checkList.map((item) => (
    <CheckBox key={item.id} id={item.id} checkItemHandler={checkItemHandler}
      checked={checkItems.includes(item.id) ? true : false} />
      // checkItems, 체크된 아이템 배열에 해당 id가 있으면 체크 없으면 해제
  ))
}

기존 코드에서는 다음과 같이 useEffect를 사용해서 문제가 있었는데 위의 코드와 같이 수정하면서
문제를 해결 했습니다.

const allCheckHandler = () => setChecked(isAllChecked);
useEffect(() => allCheckHandler(), [isAllChecked])
// useEffect 훅으로 isAllChecked 변경 시 체크함수를 활성화 해서 전체 선택 후 개별 선택 변경 시 문제 발생

작업 결과

728x90
Comments