Вот так собираю данные с чекбоксов:
const formData = new FormData(e.currentTarget.form);
const names = formData.getAll('names');
setNames(names);
Понятно. А react тогда зачем?
Если хотите продолжать в том же духе,......то обработчик события change для чекбокса, выставляющего/снимающего всё, будет выглядеть так:
const onAllSelectedChange = ({ target: { checked, form: { names } } }) => {
names.forEach(n => n.checked = checked);
setNames(checked ? Array.from(names, n => n.value) : []);
};
А для обычных чекбоксов обработчик можно переписать так (это чтобы изменение их состояния влияло на общий, которому надо будет имя задать, "allSelected"):
const onChange = ({ target: { form } }) => {
const names = new FormData(form).getAll('names');
const isAllSelected = names.length === form.names.length;
const all = form.allSelected;
all.checked = isAllSelected;
all.indeterminate = !isAllSelected && !!names.length;
setNames(names);
};
А если делать чуть менее дико, то
const Checkbox = forwardRef(({ label, ...props }, ref) =>
<label>
<input type="checkbox" ref={ref} {...props} />
{label}
</label>
);
function CheckboxGroup({
items,
label = item => item,
selected,
setSelected,
}) {
const onChange = ({ target: { checked, dataset: { index } } }) =>
setSelected(selected => checked
? [ ...selected, items[index] ]
: selected.filter(n => n !== items[index])
);
const allSelectedRef = useRef();
const onAllSelectedChange = ({ target: { checked } }) =>
setSelected(checked ? [...items] : []);
useEffect(() => {
const isAllSelected = items.length === selected.length;
allSelectedRef.current.checked = isAllSelected;
allSelectedRef.current.indeterminate = !isAllSelected && !!selected.length;
}, [ selected ]);
return (
<div className="checkbox-group">
<Checkbox
label="SELECT ALL"
defaultChecked={false}
onChange={onAllSelectedChange}
ref={allSelectedRef}
/>
{items.map((n, i) => (
<Checkbox
label={label(n)}
data-index={i}
checked={selected.includes(n)}
onChange={onChange}
/>
))}
</div>
);
}
https://jsfiddle.net/kj9wet6L/