diff --git a/README.md b/README.md
index 3c0710d2..6daae186 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,16 @@
-# react-todo-list-precourse
\ No newline at end of file
+# 미니 과제 - 할 일 목록 (React)
+
+카카오 테크 캠퍼스 2기
+
+### [STEP1] 2회차 미니과제 - 할 일 목록 (React)
+
+- 하루 또는 한 주의 할 일 목록을 업데이트하는 할 일 목록을 구현한다.
+- `React` 라이브러리를 사용하여 웹 앱으로 구현한다.
+
+## 기능 목록
+
+- 인터페이스 구현
+- 할 일 추가 기능
+- 할 일 삭제 기능
+- 할 일 완료 상태 전환 기능
+- 새로고침 시 목록 유지 기능
diff --git a/index.html b/index.html
index b021b5c8..2eb4781a 100644
--- a/index.html
+++ b/index.html
@@ -1,12 +1,12 @@
-
+
-
+ Todos
-
+
diff --git a/src/App.jsx b/src/App.jsx
new file mode 100644
index 00000000..03b67d76
--- /dev/null
+++ b/src/App.jsx
@@ -0,0 +1,40 @@
+import React, { useState, useEffect } from "react";
+import "./styles/App.css";
+import ReactDOM from "react-dom/client";
+import Header from "./components/Header";
+import TodoList from "./components/TodoList";
+import {
+ loadTodos,
+ saveTodos,
+ createAddTodo,
+ createDelTodo,
+ createToggleTodo,
+} from "./utils/utils.js";
+
+function App() {
+ const [todos, setTodos] = useState(loadTodos);
+
+ useEffect(() => {
+ saveTodos(todos);
+ }, [todos]);
+
+ const addTodo = createAddTodo(setTodos);
+ const delTodo = createDelTodo(setTodos);
+ const toggleTodo = createToggleTodo(setTodos);
+
+ return (
+ <>
+
+
+ >
+ );
+}
+
+const root = ReactDOM.createRoot(document.getElementById("app"));
+root.render(
+
+
+
+);
+
+export default App;
diff --git a/src/components/Header.jsx b/src/components/Header.jsx
new file mode 100644
index 00000000..071775f8
--- /dev/null
+++ b/src/components/Header.jsx
@@ -0,0 +1,36 @@
+import React, { useState } from "react";
+
+function Header({ addTodo }) {
+ const [newTodo, setNewTodo] = useState("");
+
+ const handleKeyDown = (e) => {
+ if (e.key === "Enter") {
+ handleAddTodo();
+ }
+ };
+
+ const handleAddTodo = () => {
+ if (newTodo.trim() !== "") {
+ addTodo(newTodo);
+ setNewTodo("");
+ }
+ };
+
+ return (
+
+ );
+}
+
+export default Header;
diff --git a/src/components/TodoItem.jsx b/src/components/TodoItem.jsx
new file mode 100644
index 00000000..02849362
--- /dev/null
+++ b/src/components/TodoItem.jsx
@@ -0,0 +1,20 @@
+import React from "react";
+
+function TodoItem({ todo, onDelete, onToggle }) {
+ return (
+
+ onToggle(todo.id)}
+ >
+ {todo.text}
+ onDelete(todo.id)}>
+ ⨯
+
+
+ );
+}
+
+export default TodoItem;
diff --git a/src/components/TodoList.jsx b/src/components/TodoList.jsx
new file mode 100644
index 00000000..f66c8bce
--- /dev/null
+++ b/src/components/TodoList.jsx
@@ -0,0 +1,19 @@
+import React from "react";
+import TodoItem from "./TodoItem";
+
+function TodoList({ todos, delTodo, toggleTodo }) {
+ return (
+
+ {todos.map((todo) => (
+
+ ))}
+
+ );
+}
+
+export default TodoList;
diff --git a/src/main.js b/src/main.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/styles/App.css b/src/styles/App.css
new file mode 100644
index 00000000..80b25169
--- /dev/null
+++ b/src/styles/App.css
@@ -0,0 +1,66 @@
+body {
+ margin: 0px;
+ padding: 0px;
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+ background-color: whitesmoke;
+ box-sizing: border-box;
+}
+
+/*HEADER*/
+.header {
+ text-align: center;
+}
+
+.header h1 {
+ color: pink;
+ font-size: 60px;
+}
+
+.header .todo-input {
+ width: 400px;
+ font-size: 20px;
+ height: 50px;
+}
+
+/*TodoItem*/
+.todo-list {
+ list-style-type: none;
+ width: 406px;
+ padding: 0px;
+ font-size: 20px;
+ background-color: white;
+ margin: 0 auto;
+}
+
+.todo-list .todo-item {
+ display: flex;
+ align-items: center;
+ height: 50px;
+ margin: 0 auto;
+ padding: 0 20px 0 20px;
+}
+.toggle {
+ accent-color: pink;
+}
+
+.todo-item input[type="checkbox"] {
+ margin-right: 1rem;
+}
+.todo-item-label {
+ width: 300px;
+}
+.todo-item .delete {
+ all: unset;
+ color: grey;
+}
+.todo-item .delete:hover {
+ color: pink;
+ cursor: pointer;
+}
+.completed .todo-item-label {
+ text-decoration: line-through;
+ text-decoration-color: pink;
+ color: grey;
+}
diff --git a/src/utils/utils.js b/src/utils/utils.js
new file mode 100644
index 00000000..5820744a
--- /dev/null
+++ b/src/utils/utils.js
@@ -0,0 +1,30 @@
+export const loadTodos = () => {
+ const savedTodos = JSON.parse(localStorage.getItem("todos-app"));
+ return savedTodos ? savedTodos : [];
+};
+
+export const saveTodos = (todos) => {
+ localStorage.setItem("todos-app", JSON.stringify(todos));
+};
+export const createAddTodo = (setTodos) => (todo) => {
+ setTodos((prevTodos) => [
+ ...prevTodos,
+ { id: Date.now(), text: todo, completed: false },
+ ]);
+};
+
+export const createDelTodo = (setTodos) => (id) => {
+ setTodos((prevTodos) => prevTodos.filter((todo) => todo.id !== id));
+};
+
+export const createToggleTodo = (setTodos) => (id) => {
+ setTodos((prevTodos) =>
+ prevTodos.map((todo) => {
+ if (todo.id === id) {
+ return { ...todo, completed: !todo.completed };
+ } else {
+ return todo;
+ }
+ })
+ );
+};