How to show the unfinished to-do count in the page title
This example demonstrates how to show the unfinished to-do count in the page title using the useTitle
hook. It includes code in both TypeScript and JavaScript versions.
TypeScript version
tsx
import { useEffect, useState } from "react";
import { useTitle } from "./useTitle";
interface Task {
id: number;
title: string;
isDone: boolean;
}
const appTasks: Task[] = [
{ id: 1, title: "Task 1", isDone: false },
{ id: 2, title: "Task 2", isDone: false },
{ id: 3, title: "Task 3", isDone: false },
{ id: 4, title: "Task 4", isDone: false },
{ id: 5, title: "Task 5", isDone: false },
];
export default function App() {
const [tasks, setTasks] = useState<Task[]>(appTasks);
const { changeTitle } = useTitle();
useEffect(() => {
const unfinishedTasks = tasks.filter((task) => !task.isDone).length;
changeTitle(`${unfinishedTasks} pending tasks`);
}, []);
// Handle check/uncheck task
const checkTask = (id: number, isDone: boolean) => {
const updatedTasks = tasks.map((task) =>
task.id === id ? { ...task, isDone } : task
);
setTasks(updatedTasks);
// Set the title depending on the number of tasks left
const unfinishedTasks = updatedTasks.filter((task) => !task.isDone).length;
const newTitle =
unfinishedTasks !== 1
? `${unfinishedTasks} pending tasks`
: `${unfinishedTasks} pending task`;
changeTitle(newTitle);
};
return (
<>
<h1>Tasks</h1>
<ul>
{tasks.map((task) => (
<li key={task.id}>
<input
type="checkbox"
checked={task.isDone}
onChange={(e) => checkTask(task.id, e.target.checked)}
/>
{task.title}
</li>
))}
</ul>
</>
);
}
typescript
import { useState } from "react";
export const useTitle = () => {
const [title, setTitle] = useState<string>(document.title);
const changeTitle = (newTitle: string) => {
document.title = newTitle;
setTitle(newTitle);
};
return { title, changeTitle };
};
JavaScript version
jsx
import { useEffect, useState } from "react";
import { useTitle } from "./useTitle";
const appTasks = [
{ id: 1, title: "Task 1", isDone: false },
{ id: 2, title: "Task 2", isDone: false },
{ id: 3, title: "Task 3", isDone: false },
{ id: 4, title: "Task 4", isDone: false },
{ id: 5, title: "Task 5", isDone: false },
];
export default function App() {
const [tasks, setTasks] = useState(appTasks);
const { changeTitle } = useTitle();
useEffect(() => {
const unfinishedTasks = tasks.filter((task) => !task.isDone).length;
changeTitle(`${unfinishedTasks} pending tasks`);
}, []);
// Handle check/uncheck task
const checkTask = (id, isDone) => {
const updatedTasks = tasks.map((task) =>
task.id === id ? { ...task, isDone } : task
);
setTasks(updatedTasks);
// Set the title depending on the number of tasks left
const unfinishedTasks = updatedTasks.filter((task) => !task.isDone).length;
const newTitle =
unfinishedTasks !== 1
? `${unfinishedTasks} pending tasks`
: `${unfinishedTasks} pending task`;
changeTitle(newTitle);
};
return (
<>
<h1>Tasks</h1>
<ul>
{tasks.map((task) => (
<li key={task.id}>
<input
type="checkbox"
checked={task.isDone}
onChange={(e) => checkTask(task.id, e.target.checked)}
/>
{task.title}
</li>
))}
</ul>
</>
);
}
javascript
import { useState } from "react";
export const useTitle = () => {
const [title, setTitle] = useState(document.title);
const changeTitle = (newTitle) => {
document.title = newTitle;
setTitle(newTitle);
};
return { title, changeTitle };
};