Работа со стейтем в функциональных и классовых компонентах немного отличается, в том плане, что в классовых ты работаешь с полным объектом, типа такого:
this.state = {
done: false,
title: "Some title",
}
и можешь обращаться напрямую к его свойствам типа this.state.done
В функциональных же ты не напрямую со стейтом работаешь, а с его свойствами типа так:
const [done] = useState(false)
Во втором случае у тебя стейт как бы всегда отсутствует, есть только его значения (которые могут быть пустыми). В первом же случае (в классовых) у тебя стейт может не быть, а может и быть. То есть если ты раз задал this.setState({done: true}), то у тебя this.state уже есть всегда в течение жизни компонента. Таким образом у тебя логическая ошибка в этом условии:
if (this.state) {
this.setState({
done: true,
});
}
У тебя всегда есть this.state и получается, что всегда задается done: true. То есть надо было проверять
if (!this.state) {
this.setState({
done: true,
});
}
то есть проверять отсутствие стейта, а не его наличие. Ну, это в твоем случае. А вообще в таких случаях делают так:
handleCardClick = () => {
this.setState({
done: !this.state?.done,
})
}
То есть устанавливают инвертированное значение.