Untitled
unknown
plain_text
4 years ago
3.0 kB
6
Indexable
import React, { useEffect, useState, useCallback, useMemo } from "react";
type TodoItem = {
id: number;
title: string;
isDone: boolean;
};
type Props = {
todos: TodoItem[];
};
enum FilterType {
All = "all",
Undone = "undone",
}
const Todos: React.FC<Props> = ({ todos: defaultTodos }) => {
const [todos, setTodos] = useState<TodoItem[]>(defaultTodos);
const [filter, setFilter] = useState<FilterType>(FilterType.All);
const handleAddTodo = useCallback(() => {
const title = prompt("What to do?");
if (!title) return;
const newTodo = { id: +Date.now(), title, isDone: false };
setTodos((prevTodos) => [...prevTodos, newTodo]);
}, []);
const makeHandleChangeTodoStatus = useCallback(
(id: number) => () => {
setTodos((prevTodos) => changeTodoStatus(prevTodos, id));
},
[]
);
const makeHandleDeleteTodo = useCallback(
(id: number) => () => {
setTodos((prevTodos) => removeFromArrById(prevTodos, id));
},
[]
);
const handleChangeFilter = useCallback(() => {
setFilter((prevFilter) =>
prevFilter === FilterType.All ? FilterType.Undone : FilterType.All
);
}, []);
useEffect(() => {
setTodos(defaultTodos);
setFilter(FilterType.All);
}, [defaultTodos]);
const visibleTodos =
filter === FilterType.Undone
? todos.filter(({ isDone }) => !isDone)
: todos;
const doneCount = useMemo(
() => todos.filter(({ isDone }) => isDone).length,
[todos]
);
const filterMessage = `Show ${
filter === FilterType.All ? "undone" : "all"
} todos`;
return (
<div>
<p>{`Done: ${doneCount} / ${todos.length}`}</p>
<ul>
{visibleTodos.map(({ id, title, isDone }) => (
<div key={id}>
<p>
{isDone && "✅ "}
{title}
</p>
<button type="button" onClick={makeHandleChangeTodoStatus(id)}>
{isDone ? "Undone" : "Done"}
</button>
<button type="button" onClick={makeHandleDeleteTodo(id)}>
Delete
</button>
</div>
))}
</ul>
<button type="button" onClick={handleAddTodo}>
Add
</button>
<button type="button" onClick={handleChangeFilter}>
{filterMessage}
</button>
<ExpensiveTree />
</div>
);
};
function changeTodoStatus(todos: TodoItem[], id: number) {
return todos.map((todo) =>
todo.id === id ? { ...todo, isDone: !todo.isDone } : todo
);
}
function removeFromArrById<T extends { id: number }>(arr: T[], id: number) {
return arr.filter((item) => item.id !== id);
}
function ExpensiveTree() {
const now = performance.now();
while (performance.now() - now < 1000) {
// Artificial delay -- do nothing for 1000ms
}
return null;
}
export default React.memo(Todos);
Editor is loading...