- useTodos
export const useTodos = () => {
const [todos, setTodos] = useState<Todo[]>([sampleTodo]);
const inProgressTodos = todos.filter((todo) => !todo.isDone);
const doneTodos = todos.filter((todo) => todo.isDone);
const addTodo = (todo: Todo) => {
setTodos((prevTodos) => [todo, ...prevTodos]);
};
const deleteTodo = (id: string) => {
setTodos((prevTodos) => prevTodos.filter((todo) => todo.id !== id));
};
const toggleTodoDone = (id: string) => {
setTodos((prevTodos) =>
prevTodos.map((todo) =>
todo.id === id ? { ...todo, isDone: !todo.isDone } : todo
)
);
};
먼저 custom hook 으로 addTodo, deleteTodo, toggleTodo 를 만들고 이후에 다른 컴포넌트에서 상태관리에 사용한다.
interface TodoFormProps {
addTodo: (todo: Todo) => void
}
const TodoForm = ({addTodo} :TodoFormProps) => {
const [title, setTitle] = useState("");
const [content, setContent] = useState("");
const onSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget)
const title = formData.get("title") as string
const content = formData.get("content") as string
if (!title || !content) {
alert("제목과 내용을 입력해주세요.");
return;
}
const nextTodo: Todo = {
id: crypto.randomUUID(),
title,
content,
isDone: false,
deadline: new Date().toLocaleString()
}
addTodo(nextTodo)
setTitle("");
setContent("");
}
만든 custom hook 을 props 로 받아서 이벤트 발생 시 작동할 로직을 만들고 Todo를 추가한 이후에 input value 를 초기화 하기 위해 useState 로 빈값을 준다. 만약 title 과 content 에 입력값이 없으면 alert 를 발생하게 했다.
- TodoItem
interface TodoItemProps {
todo: Todo
deleteTodo: (id: string) => void
toggleTodoDone: (id: string) => void
}
const TodoItem = ({todo, deleteTodo, toggleTodoDone} : TodoItemProps) => {
const {title, content, deadline, isDone, id} = todo
const onClickDelete = () => deleteTodo(id)
const onClickToggleDone = () => toggleTodoDone(id)
TodoItem 도 props 로 custom hook 을 받아와서 컴포넌트에서 이벤트 발생 시 특정 id 를 가진 Todo를 삭제하고, 토글로 완료,취소 할 때 사용된다.
- TodoList
interface TodoListProps {
todoTitle: string
todos: Todo[]
deleteTodo: (id: string) => void
toggleTodoDone: (id: string) => void
}
const TodoList = ({todoTitle, todos, deleteTodo, toggleTodoDone}: TodoListProps) => {
return (
<section>
<h2>{todoTitle}</h2>
<div>
<TodoItemList>
{todos.map((todo) => (
<TodoItem key={todo.id} todo={todo}
deleteTodo={deleteTodo} toggleTodoDone={toggleTodoDone}/>
))}
</TodoItemList>
</div>
</section>
)
}
TodoList 에서는 map 을 사용해서 todos를 랜더링 해준다.