Skip to content
Open
16 changes: 15 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
# react-todo-list-precourse
# react-todo-list-precourse
## 🍪 프로젝트 개요
2024 카카오 테크 캠퍼스 2기 FE 2차 미니과제 - 할 일 목록

## 🚧 기능 목록
### 필수 요구 사항
- [X] 할 일 추가
- [X] 할 일 삭제
- [X] 할 일 목록 보기
- [X] 할 일 완료 상태 전환

### 선택 요구 사항
- [ ] '현재 진행 중 / 완료 / 모두' 세 가지 필터링
- [ ] 해야 할 일의 총 개수 확인
- [ ] 새로고침시 작성 중인 데이터 유지
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
41 changes: 41 additions & 0 deletions src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.App {
text-align: center;
max-width: 600px;
margin: auto;
}

form {
margin-bottom: 20px;
}

input {
padding: 10px;
font-size: 16px;
width: 70%;
margin-right: 10px;
}

button {
padding: 10px 15px;
font-size: 16px;
cursor: pointer;
}

ul {
list-style: none;
padding: 0;
}

li {
padding: 10px;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #ccc;
}

li span {
cursor: pointer;
flex-grow: 1;
text-align: left;
}
48 changes: 48 additions & 0 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React, { useState } from 'react';
import TodoList from './TodoList';
import TodoForm from './TodoForm';
import TodoFilter from './TodoFilter';
import './App.css';

const App = () => {
const [todos, setTodos] = useState([]);
const [filter, setFilter] = useState('all');

const addTodo = (text) => {
if (text === '') return;
const newTodo = { text: text, id: Date.now() };
setTodos([...todos, newTodo]);
};

const deleteTodo = (todoId) => {
setTodos(todos.filter(todo => todo.id !== todoId ));
};

const filteredTodos = todos.filter(todo => {
if (filter === 'all') return true;
if (filter === 'completed') return todo.completed;
if (filter === 'active') return !todo.completed;
return true;
});

const toggleTodo = (id) => {
setTodos(
todos.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
};

return (
<div className="App">
<h1>TODO</h1>
<TodoForm addTodo={addTodo} />
<TodoList todos={filteredTodos}
deleteTodo={deleteTodo}
toggleTodo={toggleTodo}
/>
</div>
);
};

export default App;
14 changes: 14 additions & 0 deletions src/TodoFilter.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// src/TodoFilter.js
import React from 'react';

const TodoFilter = ({ setFilter }) => {
return (
<div>
<button onClick={() => setFilter('all')}>All</button>
<button onClick={() => setFilter('active')}>Active</button>
<button onClick={() => setFilter('completed')}>Completed</button>
</div>
);
};

export default TodoFilter;
25 changes: 25 additions & 0 deletions src/TodoForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React, { useState } from 'react';

const TodoForm = ({ addTodo }) => {
const [text, setText] = useState('');

const addSubmit = (e) => {
e.preventDefault();
addTodo(text);
setText('');
};

return (
<form onSubmit={addSubmit}>
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="할 일을 입력하세요."
/>
<button type="submit">Add</button>
</form>
);
};

export default TodoForm;
18 changes: 18 additions & 0 deletions src/TodoList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React from 'react';

const TodoList = ({ todos, deleteTodo, toggleTodo }) => {
return (
<ul>
{todos.map(todo => (
// todo.id => Data 객체이므로 거의 unique. => 렌더링 최적화
<li key={todo.id} style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
<div onClick={() => toggleTodo(todo.id)} style={{ backgroundColor: todo.complete ? 'black' : 'white'}} ></div>
<span onClick={() => toggleTodo(todo.id)}>{todo.text}</span>
<button onClick={() => deleteTodo(todo.id)}>Delete</button>
</li>
))}
</ul>
);
};

export default TodoList;
11 changes: 11 additions & 0 deletions src/main.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './App.css';

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('app')
);