Как правильно изменять checkbox react?
Самый лучший вариант - не использовать стейт. Вообще. Зачем он для чекбоксов? Это настолько раздуто и избыточно в 99% случаев, что хочется рвать волосенки на голове каждый раз, когда кто-то это использует. К счастью, React предоставляет uncontrolled inputs, чем я вам и рекомендую воспользоваться. Поскольку каждый раз, когда для таких компонентов используется стейт, означает, что данные сохраняются для последующей обработки, а последующая обработка в 99% случаев - отправка формы или иные ее события. 

Но конечно, если при щелчку на чекбокс надлежит вызвать какое-то событие, без коллбэка не обойтись.
Первый вариант будет лучше если у вас форма и компонентов много. Можно обрабатывать все одним хандлером:const handler = (e) => {
  const { target } = e;
  const value = target.type === 'checkbox' ? target.checked : target.value;
  const { name } = target;

  setForm( f => ({ ...f, [name]: value }));
};
Второй, если checkbox один и приложение должно как-то реагировать на его изменение. Но хандлер для лучшей читаемости, лучше вынести в переменную. Если это built-in компонент вроде input:const handler = () => {
  setX(!x);
};
И если это кастомный компонент, то необходимо использовать useCallback, чтобы предотвратить лишние перерисовки:const handler = useCallback(() => {
  setX(!x);
}, []);
Ну и неконтролируемые компоненты, упомянутые Алексей Николаев, в ряде кейсов могут быть очень удобны.