Untitled
unknown
plain_text
4 years ago
3.0 kB
5
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...