기존 CheckBox는 다른 컴포넌트에 의존성이 높고 기능도 간단했기 때문에
기능을 추가하고, hook을 만들어서 로직을 분리, 재사용할 수 있게 리팩토링 했다
전체 항목 요소와 개별 항목 요소들을 분리해서 만들고 이벤트 핸들러 함수도 각각 만들어야한다.
checked의 초기값도 상태를 기준으로 설정해야한다. (여기에서 많이 헤맸음)
- checked도 어찌됐든 스타일을 결정하는 속성이기 때문.
- 상태가 기준이 아닌 그냥 초기값을 false로 설정할 시 활성화가 안됐음.
- 개별 항목 요소의checked 기준은 상태(배열)안에 그 요소의 값이 포함되어있는지,
전체 항목 요소의 checked 기준은 모든 항목의 갯수와 체크된 항목의 갯수가 같은지로 설정해야한다.
// 오류 났던 코드 - checked의 초기 값을 상태에 따른 ture or false가 아닌 null로 설정했기 때문
return (
<div>
<label label htmlFor="all">
<input
type="checkbox"
id="all"
onChange={handleCheckedAll}
checked={checkedList.length === valueList.length ? true : null}
/>
all
</label>
{dataList.map(({ id, value }) => (
<label key={id} htmlFor={value}>
<input
key={id}
id={value}
type="checkbox"
value={value}
onChange={handelCheckedElement}
checked={ // check된 값들 중 해당 요소의 값이 포함된지만 확인하면 되는 지 몰랐다
checkedList.length === valueList.length
? false
: checkedList[0] === value
? true
: null
}
/>
{value}
</label>
))}
</div>
부모 컴포넌트에게 상태를 전달해줘야하는데 상태가 변화할 때마다 전해줘야해서 useEffect 안에 onChange(state)함수를 실행하고 전해줄 state를 의존성으로 걸어주었다.
import { useState, useEffect } from 'react';
const useCheckBox = ({
name = '',
valueList,
initialCheckeds,
filterMode,
onChange,
}) => {
const [checkedList, setCheckedList] = useState(initialCheckeds);
useEffect(() => {
onChange && onChange(name, checkedList);
}, [checkedList]);
const handleCheckedAll = e => {
const { checked } = e.target;
if (checked) {
setCheckedList(valueList);
} else {
!filterMode && setCheckedList([]);
}
};
const handleCheckedElement = e => {
const { value, checked } = e.target;
if (checked) {
checkedList.length === valueList.length
? setCheckedList([value])
: setCheckedList([...checkedList, value]);
} else {
if (filterMode && checkedList.length === 1) {
setCheckedList(valueList);
return;
}
setCheckedList(checkedList.filter(checkedItem => checkedItem !== value));
}
};
return {
checkedList,
setCheckedList,
handleCheckedAll,
handleCheckedElement,
};
};
export default useCheckBox;
return (
<div {...props}>
<label htmlFor="all">
<StyledInput
type="checkbox"
id="all"
onChange={handleCheckedAll}
checked={checkedList.length === valueList.length}
/>
<StyledButton>전체</StyledButton>
</label>
{valueList.map(value => (
<label key={value} htmlFor={value}>
<StyledInput
id={value}
type="checkbox"
value={value}
onChange={handleCheckedElement}
checked={
checkedList.length === valueList.length
? false
: checkedList.includes(value)
}
/>
<StyledButton>{convertDay([value])}</StyledButton>
</label>
))}
</div>
);