[React]Checkbox 개별선택 , 전체 선택

zzincode·2024년 1월 27일
0

React

목록 보기
12/20
post-thumbnail

게시판 checkbox 상태관리

체크된 아이템들 저장할 배열을 관리할 useState 생성

const [checkedItem, setCheckedItem] = useState([]);

checkbox 개별선택

  • handleCheck()함수 생성
const handleCheck = (e, item) => {
    const isChecked = e.target.checked;
    if (isChecked) setCheckedItem((prev) => [...prev, item.id]);
    else setCheckedItem((prev) => prev.filter((id) => id !== item.id));
  };

해당 checkbox가 checked되면 setCheckedItem배열에 해당 id를 저장
checked되지 않으면 해당 id와 일치하지 않은 id들을 setCheckedItem에 저장

  • handleCheck()함수 checkbox에 등록
{paginatedList.map((data) => (
       <tr
         key={data.id}
         className={checkedItem.includes(data.id) ? "checked" : ""}
       >
          <td>
            <input
               type="checkbox"
               onChange={(e) => handleCheck(e, data)}
               checked={checkedItem.includes(data.id) ? true : false}
            />
          </td>
          <td>{data.id}</td>
          <td>{data.title}</td>
          <td>{data.date}</td>
        </tr>
  ))}
  • checkedItem에 해당 item의 id가 포함되어 있으면 checked=true/포함되어 있지 않으면 checked=false
checked={checkedItem.includes(data.id) ? true : false}
  • checkedItem에 해당 item의 id가 포함되어 있으면 className에 checked 추가해 선택되었을 때의 style을 지정해줄 수 있음
className={checkedItem.includes(data.id) ? "checked" : ""}

checkbox 전체선택

  • handleCheckAll()함수 생성
 const handleCheckAll = (e) => {
    const isChecked = e.target.checked;
    if (isChecked) {
      const allItemIds = paginatedList.map((item) => item.id);
      setCheckedItem(allItemIds);
    } else setCheckedItem([]);
  };

전체선택 checkbox가 checked되면 allItemIds에 보여지는 페이지의 item들의 id를 저장하여 setCheckedItem에 allItemIds를 저장
checked되지 않으면 setCheckedItem 빈배열

  • handleCheckAll()함수 checkbox에 등록
<input
       type="checkbox"
       onChange={(e) => handleCheckAll(e)}
       checked={checkedItem.length === paginatedList.length}
 />

checkedItem 길이와 현 페이지의 아이템들의 길이가 같을 때 checked되도록 지정 => 길이가 같지 않을 경우 전체선택 checkbox 해제

삼항연산자를 통한 축약형

const handleCheck = (e, item) => {
  const isChecked = e.target.checked;
  setCheckedItem((prev) => (
    isChecked ? [...prev, item.id] : prev.filter((id) => id !== item.id)
  ));
};

const handleCheckAll = (e) => {
  const isChecked = e.target.checked;
  setCheckedItem(isChecked ? paginatedList.map((item) => item.id) : []);
};

전체코드

import { useState, useEffect } from "react";
import data from "../src/utils/db.json";
import "./App.css";

function App() {
  //pagination
  const [selected, setSelected] = useState(5); // 한 페이지에 보여질 게시물 수
  const [page, setPage] = useState(1); // 현재 페이지

  //checkbox
  const [checkedItem, setCheckedItem] = useState([]);

  //pagination
  const startIdx = (page - 1) * selected; // 한 페이지의 첫 게시물 인덱스
  const endIdx = startIdx + selected; // 한 페이지의 마지막 게시물 인덱스
  const paginatedList = data.slice(startIdx, endIdx); // 한 페이지의 게시물들
  const pagingCount = Math.ceil(data.length / selected); // 총 페이지 갯수
  const pageIdx = []; // 총 페이지들
  for (let i = 1; i <= pagingCount; i++) {
    pageIdx.push(i);
  }
  const handlePageChange = (page) => {
    !isNaN(page) && page >= 1 && page <= pagingCount
      ? setPage(page)
      : alert("페이지의 끝입니다.");
    setCheckedItem([]); //페이지가 넘어가면 체크 리셋

  };
  const handleSelect = (e) => {
    setSelected(Number(e.target.value));
    setPage(1);
  };

  //checkbox
  const handleCheck = (e, item) => {
    const isChecked = e.target.checked;
    setCheckedItem((prev) =>
      isChecked ? [...prev, item.id] : prev.filter((id) => id !== item.id)
    );
  };

  const handleCheckAll = (e) => {
    const isChecked = e.target.checked;
    setCheckedItem(isChecked ? paginatedList.map((item) => item.id) : []);
  };

  return (
    <div className="App">
      <select onChange={handleSelect} value={selected}>
        {[5, 6, 7, 8, 9, 10].map((option) => (
          <option key={option} value={option}>
            {option}
          </option>
        ))}
      </select>
      <table>
        <thead>
          <tr>
            <td>
              <input
                type="checkbox"
                onChange={(e) => handleCheckAll(e)}
                checked={checkedItem.length === paginatedList.length}
              />
            </td>
            <th>No</th>
            <th>Title</th>
            <th>Date</th>
          </tr>
        </thead>
        <tbody>
          {paginatedList.map((data) => (
            <tr
              key={data.id}
              className={checkedItem.includes(data.id) ? "checked" : ""}
            >
              <td>
                <input
                  type="checkbox"
                  onChange={(e) => handleCheck(e, data)}
                  checked={checkedItem.includes(data.id) ? true : false}
                />
              </td>
              <td>{data.id}</td>
              <td>{data.title}</td>
              <td>{data.date}</td>
            </tr>
          ))}
        </tbody>
      </table>
      <ul>
        <li onClick={() => handlePageChange(1)}>⏪️</li>
        <li onClick={() => handlePageChange(page - 1)}>◀️</li>
        {pageIdx.map((i) => (
          <li
            key={i}
            onClick={() => handlePageChange(i)}
            className={page === i && "active"}
          >
            {i}
          </li>
        ))}
  

        <li onClick={() => handlePageChange(page + 1)}>▶️</li>
        <li onClick={() => handlePageChange(pagingCount)}>⏩️</li>
      </ul>
    </div>
  );
}

export default App;


❖참고사항
console로 checkItem 출력하면 선택한 아이템이 제대로 들어가지 않는 것을 볼 수 있었다.
하지만 useState함수는 비동기적으로 동작할 수 있기 때문에 console.log(checkedItem)는 즉시 실행되지만 setCheckedItem함수가 상태를 업데이트하고 그 값이 반영되는데는 시간이 걸릴 수 있기 때문이다.
즉시 업데이트 되는 것을 확인하고 싶다면 useEffect를 사용하면 가능하다.

useEffect(() => {
    console.log(checkedItem);
  }, [checkedItem]);

0개의 댓글