Это первый финальный проект для портфолио. Todo App — классический проект, который демонстрирует понимание основ React.
Что вы создадите:
1. Создание задач
- Текст задачи (обязательно)
- Приоритет: низкий / средний / высокий
- Дедлайн (опционально)
2. Управление задачами
- Отметить как выполненную
- Редактировать текст
- Удалить задачу
3. Фильтрация
- Все / Активные / Выполненные
- По приоритету
- Поиск по тексту
4. Сортировка
- По дате создания
- По приоритету
- По дедлайну
src/
├── components/
│ ├── TodoForm.jsx # Форма создания
│ ├── TodoItem.jsx # Отдельная задача
│ ├── TodoList.jsx # Список задач
│ ├── TodoFilters.jsx # Фильтры и поиск
│ └── TodoStats.jsx # Статистика
├── hooks/
│ ├── useTodos.js # Логика управления
│ └── useLocalStorage.js
├── utils/
│ └── filters.js
└── App.jsx| Критерий | Баллы |
|----------|-------|
| Работающий CRUD | 30 |
| Фильтрация и поиск | 20 |
| localStorage persistence | 15 |
| Адаптивный UI | 15 |
| Чистый код (компоненты) | 10 |
| Дополнительные фичи | 10 |
const todo = {
id: 'uuid',
text: 'Изучить React',
completed: false,
priority: 'high', // 'low' | 'medium' | 'high'
createdAt: '2024-01-15T10:00:00Z',
deadline: '2024-01-20T23:59:59Z' // optional
}function useTodos() {
const [todos, setTodos] = useState([])
const addTodo = (text, priority, deadline) => { ... }
const toggleTodo = (id) => { ... }
const updateTodo = (id, updates) => { ... }
const deleteTodo = (id) => { ... }
return { todos, addTodo, toggleTodo, updateTodo, deleteTodo }
}Разделите UI на независимые компоненты с чёткой ответственностью.
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos))
}, [todos])Добавьте состояние для фильтров и примените их к списку.
Архитектура приложения: useTodos hook
// Custom Hook для управления задачами
function useTodos() {
// Загрузка из localStorage при инициализации
const [todos, setTodos] = React.useState(() => {
const saved = localStorage.getItem('todos')
return saved ? JSON.parse(saved) : []
})
// Сохранение в localStorage при изменении
React.useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos))
}, [todos])
// Создание задачи
const addTodo = (text, priority = 'medium', deadline = null) => {
const newTodo = {
id: Date.now().toString(),
text,
completed: false,
priority,
deadline,
createdAt: new Date().toISOString()
}
setTodos(prev => [newTodo, ...prev])
return newTodo
}
// Переключение статуса
const toggleTodo = (id) => {
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
))
}
// Обновление задачи
const updateTodo = (id, updates) => {
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, ...updates } : todo
))
}
// Удаление задачи
const deleteTodo = (id) => {
setTodos(prev => prev.filter(todo => todo.id !== id))
}
// Очистка выполненных
const clearCompleted = () => {
setTodos(prev => prev.filter(todo => !todo.completed))
}
// Статистика
const stats = {
total: todos.length,
completed: todos.filter(t => t.completed).length,
active: todos.filter(t => !t.completed).length,
highPriority: todos.filter(t => t.priority === 'high' && !t.completed).length
}
return {
todos,
addTodo,
toggleTodo,
updateTodo,
deleteTodo,
clearCompleted,
stats
}
}
// === Демонстрация ===
console.log('=== useTodos Hook Demo ===\n')
// Симуляция React-подобного state
let todosState = []
const setTodos = (fn) => {
todosState = typeof fn === 'function' ? fn(todosState) : fn
}
// Функции
const addTodo = (text, priority = 'medium') => {
const newTodo = {
id: Date.now().toString(),
text,
completed: false,
priority,
createdAt: new Date().toISOString()
}
setTodos(prev => [newTodo, ...prev])
console.log('✅ Added:', text)
return newTodo
}
const toggleTodo = (id) => {
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
))
}
// Тестирование
addTodo('Создать React проект', 'high')
addTodo('Написать компоненты', 'medium')
addTodo('Добавить стили', 'low')
console.log('\nTodos:', todosState.map(t =>
(t.completed ? '✅' : '⬜') + ' [' + t.priority + '] ' + t.text
))
toggleTodo(todosState[0].id)
console.log('\nПосле toggle:')
console.log(todosState.map(t =>
(t.completed ? '✅' : '⬜') + ' ' + t.text
))
const stats = {
total: todosState.length,
completed: todosState.filter(t => t.completed).length,
active: todosState.filter(t => !t.completed).length
}
console.log('\nStats:', stats)Это первый финальный проект для портфолио. Todo App — классический проект, который демонстрирует понимание основ React.
Что вы создадите:
1. Создание задач
- Текст задачи (обязательно)
- Приоритет: низкий / средний / высокий
- Дедлайн (опционально)
2. Управление задачами
- Отметить как выполненную
- Редактировать текст
- Удалить задачу
3. Фильтрация
- Все / Активные / Выполненные
- По приоритету
- Поиск по тексту
4. Сортировка
- По дате создания
- По приоритету
- По дедлайну
src/
├── components/
│ ├── TodoForm.jsx # Форма создания
│ ├── TodoItem.jsx # Отдельная задача
│ ├── TodoList.jsx # Список задач
│ ├── TodoFilters.jsx # Фильтры и поиск
│ └── TodoStats.jsx # Статистика
├── hooks/
│ ├── useTodos.js # Логика управления
│ └── useLocalStorage.js
├── utils/
│ └── filters.js
└── App.jsx| Критерий | Баллы |
|----------|-------|
| Работающий CRUD | 30 |
| Фильтрация и поиск | 20 |
| localStorage persistence | 15 |
| Адаптивный UI | 15 |
| Чистый код (компоненты) | 10 |
| Дополнительные фичи | 10 |
const todo = {
id: 'uuid',
text: 'Изучить React',
completed: false,
priority: 'high', // 'low' | 'medium' | 'high'
createdAt: '2024-01-15T10:00:00Z',
deadline: '2024-01-20T23:59:59Z' // optional
}function useTodos() {
const [todos, setTodos] = useState([])
const addTodo = (text, priority, deadline) => { ... }
const toggleTodo = (id) => { ... }
const updateTodo = (id, updates) => { ... }
const deleteTodo = (id) => { ... }
return { todos, addTodo, toggleTodo, updateTodo, deleteTodo }
}Разделите UI на независимые компоненты с чёткой ответственностью.
useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos))
}, [todos])Добавьте состояние для фильтров и примените их к списку.
Архитектура приложения: useTodos hook
// Custom Hook для управления задачами
function useTodos() {
// Загрузка из localStorage при инициализации
const [todos, setTodos] = React.useState(() => {
const saved = localStorage.getItem('todos')
return saved ? JSON.parse(saved) : []
})
// Сохранение в localStorage при изменении
React.useEffect(() => {
localStorage.setItem('todos', JSON.stringify(todos))
}, [todos])
// Создание задачи
const addTodo = (text, priority = 'medium', deadline = null) => {
const newTodo = {
id: Date.now().toString(),
text,
completed: false,
priority,
deadline,
createdAt: new Date().toISOString()
}
setTodos(prev => [newTodo, ...prev])
return newTodo
}
// Переключение статуса
const toggleTodo = (id) => {
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
))
}
// Обновление задачи
const updateTodo = (id, updates) => {
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, ...updates } : todo
))
}
// Удаление задачи
const deleteTodo = (id) => {
setTodos(prev => prev.filter(todo => todo.id !== id))
}
// Очистка выполненных
const clearCompleted = () => {
setTodos(prev => prev.filter(todo => !todo.completed))
}
// Статистика
const stats = {
total: todos.length,
completed: todos.filter(t => t.completed).length,
active: todos.filter(t => !t.completed).length,
highPriority: todos.filter(t => t.priority === 'high' && !t.completed).length
}
return {
todos,
addTodo,
toggleTodo,
updateTodo,
deleteTodo,
clearCompleted,
stats
}
}
// === Демонстрация ===
console.log('=== useTodos Hook Demo ===\n')
// Симуляция React-подобного state
let todosState = []
const setTodos = (fn) => {
todosState = typeof fn === 'function' ? fn(todosState) : fn
}
// Функции
const addTodo = (text, priority = 'medium') => {
const newTodo = {
id: Date.now().toString(),
text,
completed: false,
priority,
createdAt: new Date().toISOString()
}
setTodos(prev => [newTodo, ...prev])
console.log('✅ Added:', text)
return newTodo
}
const toggleTodo = (id) => {
setTodos(prev => prev.map(todo =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
))
}
// Тестирование
addTodo('Создать React проект', 'high')
addTodo('Написать компоненты', 'medium')
addTodo('Добавить стили', 'low')
console.log('\nTodos:', todosState.map(t =>
(t.completed ? '✅' : '⬜') + ' [' + t.priority + '] ' + t.text
))
toggleTodo(todosState[0].id)
console.log('\nПосле toggle:')
console.log(todosState.map(t =>
(t.completed ? '✅' : '⬜') + ' ' + t.text
))
const stats = {
total: todosState.length,
completed: todosState.filter(t => t.completed).length,
active: todosState.filter(t => !t.completed).length
}
console.log('\nStats:', stats)Создай полнофункциональный Todo App. Реализуй добавление, удаление, редактирование задач. Добавь фильтрацию по статусу и приоритету, поиск по тексту. Данные должны сохраняться в localStorage.
localStorage: JSON.stringify(todos). addTodo: [todo, ...prev]. toggleTodo: !todo.completed. deleteTodo: todo.id !== id.