SMALL
0309 ๐
๐ช TypeScript
์ฌ์ฉํด To-Do List ๋ง๋ค๊ธฐ - props-drilling
๋ฐฉ์
ํํฐ๋์ ๋ต์ ์ฝ๋๋ฅผ ์ดํด๋ณด์!
ํ์ง๋ง ๋ญ๊ฐ ์ฝ๋์์ ์๋ชป ๋ ๊ฒ์ธ์ง ์๋ฌ๊ฐ ๋ ์์๊ณ ใ ใ
๋ด๊ฐ ์ฝ๋ ์์ ํด์ ํด๊ฒฐํ๊ธด ํ๋ค.
๊ฐ์์์์ ๋ฌ๋ฆฌ hook์ ๋ง๋ค์ด ์ฌ์ฉํด์ ๊ฐ์ ๋ ์ฝ๋์ ๋ค๋ฅด๊ธฐ๋ ํ๋ค.
- ๋ต์ ์ฝ๋์ to-do list ๋ ๊ฐ์ํ๋ ํฌ๋๋ฆฌ์คํธ๋ผ todo๋ id, title, isDone(์๋ฃ์ฌ๋ถ) ์ key๋ค๋ก๋ง ๊ฐ๋จํ ๊ตฌ์ฑ๋จ.
App.tsx
>TodoList.tsx
์ปดํฌ๋ํธ >TodoItem.tsx
์ปดํฌ๋ํธ ๋ฐฉ์์ผ๋ก ์ํด์๋ค.- TodoList๊ฐ ๊ฑฐ์ ๋ฉ์ธ์ด๋ค.
์ด ์ปดํฌ๋ํธ์์ hook์ importํด ์ฌ์ฉํ๋ฉฐ, TodoItem์ผ๋ก ์ด hook์์ ๋ฐ์ ๋ฆฌํด๊ฐ์ props ํํ๋ก ์ ๋ฌํด์ค๋ค - hook์ TodoList.hooks.ts ์ ํ๋ ์๋ useTodo( ) ๋ฅผ ์ฌ์ฉํ๋ค
<TodoList.tsx> - ๋ฉ์ธ
import React from "react";
import { TodoItem } from "./Todo";
import { useTodo } from "./TodoList.hooks";
export type Todo = {
// ์ฌ๊ธฐ์ ์ด๋ ๊ฒ Todo ์ id,title,isDone ํ์
์ง์ ํด์คฌ๊ธฐ๋๋ฌธ์, ๋ค๋ฅธ ๊ณณ์์๋ ํ์
์ธ ๋
// id : string ์ด๋ผ๊ณ ์ง์ ์จ์ค๋ ๋์ง๋ง, ์ด๊ฑธ ์์ฉํด์, id: Todo["id"] ๋ผ๊ณ ๋ ์ธ ์ ์๋ค
// ์๋ง ์ด๋ ๊ฒ ์ฒ๋ฆฌํด์ฃผ๋ฉด ์ข์ ์ ์ด, ๋ง์ฝ ์ด ํ์
๋ด์์ id: number๋ก ๋ฐ๊พธ๋ฉด ๋ง๊ฒ ์์์
// id:Todo["id"]๋ id:number๊ฐ ๋๋ ๊ฒ
id: string;
title: string;
isDone: boolean;
}; // ์ด ์์์์๋ todo๋ด์ฉ์ผ๋ก title๋ง input์ผ๋ก ๋ฃ๋๋ก ๋ค๋ฃธ (๋ฐ๋กcontent,date์์)
export const TodoList: React.FC = () => {
const {
todos,
title,
handleTitleChange,
handleAddTodo,
handleDeleteTodo,
handleToggleTodo,
} = useTodo(); // ์ด hook์์ todos, title ๋ฑ ๋ฆฌํดํด์ฃผ๋๋ก ๋์ด์์ / ํ
์ผ๋ก ๊ฐ์ํํด์ฃผ๊ธฐ! state์ ์ธ๋ ๋ค hook์์ ์ฒ๋ฆฌ
return (
<div>
<input value={title} onChange={handleTitleChange} type="text" />
<button
onClick={() => {
handleAddTodo(title);
}}
>
Add Todo
</button>
<ul>
{todos.map((todo) => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={handleToggleTodo}
onDelete={handleDeleteTodo}
/>
))}
</ul>
</div>
);
};
<TodoList.hooks.ts> - hook์ด ์๋ tsํ์ผ
์ด hook, useTodo ์์์ todos, title
์ state๋ ์ ์ธํ๊ณ (useState)
title input ์ onChange ํจ์์ธ handleTitleChange
,
todo ๋ฅผ ์ถ๊ฐ, ์ญ์ , ์๋ฃ์ฌ๋ถํ ๊ธํ๋ handleAddTodo, handleDeleteTodo, handleToggleTodo
ํจ์๋ฅผ ๋ชจ๋ ์จ์ค.
๊ทธ๋์ ์ด๋ฌํ todos, title, handleTitleChange, handleAddTodo, handleToggleTodo, handleDeleteTodo
๋ฅผ ๋ชจ๋ ๋ฆฌํด๊ฐ์ผ๋ก ๋ฐํํด์ฃผ๋ ๋ฐฉ์์ด๋ค.
import { useState } from "react";
import { Todo } from "./TodoList";
export const useTodo = () => {
const [todos, setTodos] = useState<Todo[]>([]);
// ์๋ title state์, handleTitleChange์ด ์์๋ ๊ฑฐ ๊ฐ์! (๋น ์ง๋ฏ?)
// ์๋๋ ๋ด๊ฐ ์์ฑ
const [title, setTitle] = useState("");
const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setTitle(e.target.value);
};
const handleAddTodo = (title: Todo["title"]) => {
const newTodo: Todo = {
id: crypto.randomUUID(),
title,
isDone: false,
};
setTodos((prev) => [...prev, newTodo]);
setTitle("");
};
const handleToggleTodo = (id: Todo["id"]) => {
setTodos((prev) =>
prev.map((todo) =>
todo.id === id ? { ...todo, isDone: !todo.isDone } : todo
)
);
};
const handleDeleteTodo = (id: Todo["id"]) => {
setTodos((prev) => prev.filter((todo) => todo.id !== id));
};
return {
// ์ด ํ
์์ ๋ฆฌํดํด์ฃผ๋ ๊ฐ๋ค
todos,
title,
handleTitleChange,
handleAddTodo,
handleToggleTodo,
handleDeleteTodo,
};
};
<Todo.tsx> - to-do item
- todoitem ์ ๋ด์ฉ์ด ๋ค์ด์๋ค
- ์ปดํฌ๋ํธ ํ์ ์ผ๋ก : React.Fc<ํ๋กญ์ค ํ์ > ์ ์จ์ฃผ๋ฉด ๋จ. ์์์ TodoProps ํ์ ์ ๋ง๋ค์ด๋์์ผ๋, ๊ทธ๊ฑธ <>์์ ๋ฃ๊ธฐ - ( ์ ๋ค๋ฆญ < > ) (๋ฌผ๋ก ์ด ๋ฐฉ์์ ๊ผญ ์ธ ํ์์๋ค)
- FC: Functional Component ์ค์๋ง
- React.Fc ๋ก ํ์
์ ์จ์ฃผ๋ ๊ฑด React 18๋ฒ์ ์ด์ ๋ฐฉ์์ด๋ผ๊ณ ๋ค์์ผ๋ฉฐ, ์ฌ๊ธฐ์ ์๋ฌต์ ์ผ๋ก children์ด ํฌํจ๋์ด์์ด children props์๋ํ ํ์
์ฒดํน์ด ๋ช
ํํ์ง ์๋ค๋ ๋ฌธ์ ์ ์ด ์์ด ์ฌ์ฉ์ ์ง์ํ์๋ ์๊ธฐ๊ฐ ์์๋ค๊ณ ํ๋ค.
- ๊ทผ๋ฐ ์ด ๋ถ๋ถ์ด ํ์ฌ ์ข ์์ ์ด ๋๊ฑด์ง? ํํผ ๋ค์ ์จ๋ ๋๋ค๋ ์์ผ๋ก ๋ค์ ๊ฑฐ ๊ฐ๋ค. ํ์ค์น์์ ..!
import React from "react";
import { Todo } from "./TodoList"; // ํ์
์ํฌํธ
type TodoProps = {
todo: Todo;
onToggle: (id: Todo["id"]) => void; // (id: string) => .. ๊ณผ ๊ฐ๋ค
onDelete: (id: Todo["id"]) => void;
};
export const TodoItem: React.FC<TodoProps> = ({ todo, onToggle, onDelete }) => {
return (
<li>
<input
type="checkbox" // ์ฌ๊ธฐ์๋ ์๋ฃ/์ทจ์๋ฒํผ์ด ์๋๋ผ, ์ฒดํฌ๋ฐ์ค [v] input์ผ๋ก toggle ํด์ฃผ๊ณ ์์
checked={todo.isDone}
onChange={() => onToggle(todo.id)} // ์ฆ, handleToggleTodo ํจ์. ์ธ์๊ฐ ์์ผ๋ ์ฝ๋ฐฑํจ์๋ก ๋ฃ๋๋ค
/>
{todo.title}
<button onClick={() => onDelete(todo.id)}>Delete</button>
</li>
);
};
SMALL