보통 <CheckBox />
는 <FormControlLabel />
컴포넌트에서 control 속성에 정의하여 사용합니다.
checked 속성이 true면 체크로 표시되고, false면 체크가 해제됩니다.
...
/** 상품 선택 handler
* 해당 상품의 인덱스, event, 해당 목록 state, 해당 목록 useState를 받음
*/
const handleCheckedChange = (index, event, checkedLists, setCheckedLists) => {
const itemRef = [...checkedLists];
itemRef[index] = event.target.checked;
setCheckedLists([...itemRef]);
};
...
<FormControlLabel
control={
<Checkbox
checked={isCheckedNoTaxPrducts[index]}
onChange={event =>
handleCheckedChange(
index,
event,
isCheckedNoTaxPrducts,
setIsCheckedNoTaxProducts,
)
}
/>
}
sx={{ pl: "2px", mr: 0 }}
/>
...
onChange
를 통해서 클릭 시event.target.checked
가 true, false로 값을 바꿔준다.- 처음 리스트의 길이 만큼의 빈 배열에 모두 false로 채운 후 map을 통해 뿌려진
<FormControlLabel />
의 특정 checked의 값을 true로 바꿔주기 위해 index값을 이용했다.
indeerminate 속성을 통해서 전체 선택 기능을 추가했습니다.
...
/** 상품 전체 선택 handler
* 해당 상품의 event, 해당 목록 state, 해당 목록 useState를 받음
*/
const handleCheckedChangeAll = (event, checkedLists, setCheckedLists) => {
const itemRef = [...checkedLists];
itemRef.forEach((_item, index) => (itemRef[index] = event.target.checked));
setCheckedLists([...itemRef]);
};
/** 상품 checked 확인 handelr
* 상품 목록 state를 받음
*/
const handleIndeterminate = array => {
if (array.every(item => item === false)) {
return false;
} else if (array.every(item => item === true)) {
return false;
} else {
return true;
}
};
...
<FormControlLabel
control={
<Checkbox
checked={isCheckedNoTaxPrducts.every(
item => item === true,
)}
indeterminate={handleIndeterminate(
isCheckedNoTaxPrducts,
)}
onChange={event => {
handleCheckedChangeAll(
event,
isCheckedNoTaxPrducts,
setIsCheckedNoTaxProducts,
);
}}
/>
}
sx={{ mr: 0 }}
/>
- 전체를 check해주는 을 눌렀을 때 handleCheckedChangeAll을 실행해서 배열의 모든 값을 true로 바꿔주거나 false로 바꿔줍니다.
- checked 속성은 모든 배열이 true일 때에만 true를 반환해서 checked가 될 수 있도록 했습니다.
- indeterminate는 handleIndeterminate에서 배열이 모두 true이거나 모두 false면 리턴 false, 이 외에는 true를 반환해서 아래와 같이 (-)가 나오도록 했습니다. (더 좋은 조건문이 없을까,, 고민해봤는데 우선 저렇게 함수로 만들어서 했습니다..!)
useEffect(() => {
if (checkedNoTaxCancel.every(item => item === true)) {
setNoTaxSelectAll(true);
} else {
setNoTaxSelectAll(false);
}
}, [checkedNoTaxCancel]);
useEffect(() => {
if (checkedHasTaxCancel.every(item => item === true)) {
setHasTaxSelectAll(true);
} else {
setHasTaxSelectAll(false);
}
}, [checkedHasTaxCancel]);
interminate
속성을 모를 때에는 위처럼 전체 선택을 하게 해주는 체크박스를useState
에 저장하고useEffect
를 사용해서 값이 변화할 때마다checked
를 업데이트 해주었습니다..- 또한 리렌더링 될 때 useEffect도 실행, setState의 값이 변경될 때 또 useEffect가 실행되므로 렌더링이 두번 발생하게 됩니다.
<CheckBox />
를 handleChange 할 때, 조건을 계산해서 처리하는 것이 바른 방법이고, state가 변할 때마다 수행하는 것은 깜박임이 문제될 수 있다고 합니다.
GOOD