COCO World

[React] input 체크박스 checkbox 전체선택, 부분선택 에러 해결 본문

에러 기록지

[React] input 체크박스 checkbox 전체선택, 부분선택 에러 해결

코코월드주인장 2023. 3. 20. 11:59

1. 사건 해결장면

2. 코드 현황

state들

  // 유저리스트 데이터 state
  const [userList, setUserList] = useState([] as any);

  // 검색 조건 state
  const [searchTerm, setSearchTerm] = useState('');
  const [filterList, setFilterList] = useState([] as any);

체크 박스 관련 변수들

  // 개별 항목을 체크했을 때의 state
  const [isCheckingBox, setIsCheckingBox] = useState(false);
  // 체크항목 저장하는 변수 state
  const [checkedArr, setCheckedArr] = useState<String[]>([]);
  // 개별 체크표시 핸들러
  const checkHandler = (e: React.ChangeEvent<HTMLInputElement>, id: any) => {
    setIsCheckingBox(!isCheckingBox);
    checkedItemHandler(e.target.checked, id);
  };
  // 전체 체크박스 선택 핸들러
  const allCheckHandler = (isChecked: boolean) => {
    if (isChecked) {
      const idArray = [] as any;
      userList.forEach((item: any) => {
        console.log('allchecked handler', userList)
        if (checkedArr.includes(item.clientId)) {
          // check 배열에 전체선택 품목 중 포함되어있는 것이 있다면 빼고 push
        } else {
          checkedArr.push(item.clientId);
          setCheckedArr(checkedArr);
        }
      });
    } else {
      setCheckedArr([]);
    }
  };
  
  // 체크아이템 변수에 담는 핸들러
  const checkedItemHandler = (isChecked: any, id: any) => {
    if (isChecked) {
      // 배열 추가 -> 객체 추가면 checkedArr.add
      checkedArr.push(id);
      setCheckedArr(checkedArr);
      // setCheckedArr([...checkedArr, id])
    } else if (!isChecked || checkedArr.includes(id)) {
      setCheckedArr((checkedArr) => checkedArr.filter((item) => item !== id));
    }
  };

useEffect 부분

  // 페이지 렌더링하자마자 데이터 get
  useEffect(() => {
    getUserData();

    // setCount(userList.length);
    setIndexOfLastPost(currentPage * postPerPage);
    setIndexOfFirstPost(indexOfLastPost - postPerPage);
    setCurrentPosts(userList.slice(indexOfFirstPost, indexOfLastPost));

  }, [currentPage, indexOfLastPost, indexOfFirstPost, postPerPage, getUserData]);

전체 체크박스 UI

        <CardHeader>
          <Percentage width="10%">
            전체선택
            <input
              type="checkbox"
              onChange={(e: any) => allCheckHandler(e.target.checked)}
              checked={checkedArr.length === userList.length ? true : false}
            />
          </Percentage>
          <Percentage width="20%">고객명</Percentage>
          <Percentage width="50%">연락처</Percentage>
          <Percentage width="20%">생성일</Percentage>
        </CardHeader>

부분 체크박스 UI

        <CardContainer>
          {userList.slice(indexOfFirstPost, indexOfLastPost) &&
          userList.length > 0 ? (
            userList
              .slice(indexOfFirstPost, indexOfLastPost)
              .map((item: any) => {
                return (
                  <CardInBox key={item.clientId}>
                    <Percentage width="10%">
                      <input
                        type="checkbox"
                        checked={checkedArr.includes(item.clientId)}
                        onChange={(e: any) => checkHandler(e, item.clientId)}
                      />
                    </Percentage>
                    <Percentage width="20%">{item.clientName}</Percentage>
                    <Percentage width="50%">{item.contact}</Percentage>
                    <Percentage width="20%">{item.createdAt}</Percentage>
                  </CardInBox>
                );
              })
          ) : (
            <div>No Post. </div>
          )}
        </CardContainer>

 

3. 에러 설명

: useEffect의 의존성배열에 처음 페이지를 읽어올 때 리스트를 담는 state인 userList 를 담았었다가

 무한렌더링이 발생하여 제거하였다.  그 후 전체 체크 선택이 되지 않는 상황이 발생하였다.

 

4. 에러 해결

그 전에는 리스트를 담은 값들을 forEach를 돌리면서 전체선택을 눌렀을 경우, 기존에 이미 체크박스가 선택된 값을 담아놓는 checkedArr 배열에 담겨있지 않다면 바로 넣어주고 setState로 업로드 했었다면, 

 수정한 코드에서는 allArray라는 새로운 배열을 선언하고, 전체선택을 눌렀을 때 선택된 전체 리스트값들을 allArray에 담아 checkedArr 배열에 push해주었다.

const allCheckHandler = (isChecked: boolean) => {
    if (isChecked) {
      const allArray = [] as any;
      userList.forEach((item: any) => {
        console.log('allchecked handler', userList)
        if (allArray.includes(item.clientId)) {
          // check 배열에 전체선택 품목 중 포함되어있는 것이 있다면 빼고 push
        } else {
          // checkedArr.push(item.clientId);
          // setCheckedArr(checkedArr);
          allArray.push(item.clientId);
          setCheckedArr(idArray);
        }
      });
    } else {
      setCheckedArr([]);
    }
    console.log('allcheck checkedArr', checkedArr)
  };