Unable to accurately keep a running total of checkboxes checked in a Typescript ToDo app

My goal is to track the total number of checkboxes that are checked (and also subtracting from the total when they become unchecked). My motivation behind this is show some sort of announcement once x number of boxes become checked. (For now I’ll just settle for a console.log message.)

At the moment, the total only increases if I click the checkbox for an individual task multiple times. If “add” 3 tasks and click each of those 3 checkboxes one time, I the same log of a total 0 three times (“checkCount”). I’ve included a screenshot of what I see. I’ve also included my primary App.tsx and ToDoTask.tsx files.

I want to understand the logic and I suspect it has something to do with the fact that I’m mapping/creating tasks?

Any thoughts are greatly appreciated!

enter image description here

App.tsx

import React, { useState, ChangeEvent } from "react";
import "./App.css";
import { ITask } from "./Interfaces";
import TodoTask from "./Components/TodoTask";
import todoImg from "./todo.png";
import { v4 as uuidv4 } from "uuid";

// React func comp type `React.FC`
const App: React.FC = () => {
  const [task, setTask] = useState<string>(""); //type string

  // state hook with type `ITask[]`-- array of objects with properties `taskName` and `id`
  const [todo, setTodo] = useState<ITask[]>([]);

  const [taskCount, setTaskCount] = useState<number>(1);

  // event handler for handling changes in input fields--typing is specified with `ChangeEvent<HTMLInputElement>`; return nothing so void
  const handleChange = (event: ChangeEvent<HTMLInputElement>): void => {
    if (event.target.name === "task") {
      setTask(event.target.value);
    }
  };

  const addTask = (): void => {
    //return nothing so void
    // creates new task object w/properties `taskName` and `deadline`
    const newTask = {
      id: uuidv4(),
      taskName: task,
    };
    //console.log(newTask.id);
    // adds new task object to the `todo` state and resets input fields
    setTodo([...todo, newTask]);
    setTask("");
    setTaskCount(taskCount + 1);
    console.log("taskCount", taskCount);
    /*  if (taskCount === 10) {
      alert("10 tasks: you can do this!");
    } */
  };

  const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
    //type React.KeyboardEvent<HTMLInputElement
    if (event.key === "Enter") {
      addTask();
    }
  };

  // event handler for completing a task; takes in a `taskNameToDelete` string type; returns nothing so voide
  const completeTask = (taskNameToDelete: string): void => {
    // filters out the task with the specified name and updates the `todo` state
    setTodo(
      todo.filter((task) => {
        setTaskCount(taskCount - 1);
        console.log("taskCount", taskCount - 2);
        return task.id !== taskNameToDelete;
      })
    );
  };
  //changed this from task.taskName to task.id so that tasks are deleted by unique id (uuid)
  //before, when deleting based on taskName, if multiples tasks had the same text, ALL of them would be deleted when one was deleted

  return (
    <div className="App">
      <div className="header">
        <div className="banner">
          <img src={todoImg} alt="to do banner" />
        </div>
        <div className="entry">
          <h1>To-Do List</h1>
          <div className="inputContainer">
            <input
              type="text"
              name="task"
              placeholder="Add a task:"
              value={task}
              onChange={handleChange}
              onKeyDown={handleKeyDown}
            />
            <button onClick={addTask}>Add</button>
          </div>
        </div>
      </div>
      <div className="todoList">
        {todo.map((task: ITask) => {
          return (
            <TodoTask
              key={task.id}
              task={task}
              completeTask={() => completeTask(task.id)} //(see delete function above--was just completeTask=completeTask before)
            />
          );
        })}
      </div>
    </div>
  );
};

export default App;

TodoTask.tsx

import { ITask } from "../Interfaces";
import { useState } from "react";

// Props interface defines the shape of the data that is passed as props to the TodoTask component
interface Props {
  // task is of type ITask from "../Interfaces"
  task: ITask;

  // takes a string parameter taskNameToDelete and returns nothing so type is void
  completeTask(taskNameToDelete: string): void;
}

const TodoTask = ({ task, completeTask }: Props) => {
  const [isChecked, setIsChecked] = useState(false);
  const [checkCount, setCheckCount] = useState<number>(0);

  const handleCheckboxClick = () => {
    setIsChecked(!isChecked);
    setCheckCount(checkCount + 1);
    console.log("checkCount", checkCount);
  };

  return (
    <div className="task">
      <div className="inputContainer">
        <input
          type="checkbox"
          onChange={handleCheckboxClick}
          checked={isChecked}
        />
        <div className="content">
          <span style={{ backgroundColor: isChecked ? "#00800080" : "" }}>
            {task.taskName}
          </span>
        </div>
      </div>
      <div className="buttonContainer">
        <button
          onClick={() => {
            completeTask(task.taskName);
          }}
        >
          X
        </button>
      </div>
    </div>
  );
};
export default TodoTask;

While I’ve tried putting this into either file and in different locations within the code, I’ve primarily tried track the total with state:

const [checkCount, setCheckCount] = useState<number>(0);

Tracking it with a function:

  const handleCheckboxClick = () => {
    setIsChecked(!isChecked);
    setCheckCount(checkCount + 1);
    console.log("checkCount", checkCount);
    if (!isChecked) {
      alert("You did it!");
    }
  };

And attaching that to the input element:

<input type="checkbox" onChange={handleCheckboxClick} checked={isChecked}/>