Одне React-завдання, яке демонструє ключові навички на співбесіді
Співбесіди на позиції React-розробника часто включають тестове завдання чи live-coding, де потрібно за короткий час продемонструвати свої знання. Одне з найкращих способів оцінити кандидата – дати йому цілісне завдання, яке покриє кілька ключових аспектів React: роботу зі станом, взаємодію з API, обробку подій та оптимізацію. У цій статті ми розглянемо одне завдання, яке можна попросити виконати на співбесіді, і розберемо, чому воно показує ключові навички.
Опис завдання
- Завдання: Створити простий TODO-додаток із можливістю:
- Додавати нові завдання;
- Відмічати їх як виконані;
- Видаляти їх із списку;
- Зберігати та отримувати список завдань із фейкового API (можна використати mock API або json-server).
- Вимоги:
- Використати React Hooks (useState, useEffect) або Redux (залежно від вимог співбесіди);
- Зробити форму додавання завдання;
- Продемонструвати обробку помилок (наприклад, якщо API недоступний).
- Оптимізація:
- Реалізувати мінімальний кеш або показати, як уникнути зайвих запитів;
- Пояснити підхід до мемоізації (наприклад, useMemo або React.memo).
- UI (базовий або із бібліотекою Material UI / Bootstrap) – не критично, головне показати інтуїтивну взаємодію.
Чому саме TODO-додаток?
- Розуміння стану (state management): TODO-список відмінно демонструє роботу зі станом: додавання, видалення й оновлення елементів.
- Обробка користувацьких подій: Додавання завдання пов’язане з формою, а відмітка “cвиконано” – з чекбоксом.
- Взаємодія з API: Можливість завантажувати завдання з сервера та відправляти зміни.
- Оптимізація: Якщо додаток стає більшим, потрібно думати про ефективні ререндери.
Приклад рішення
1. Структура проєкту
src/
components/
TodoList.js
TodoItem.js
AddTodoForm.js
App.js
api.js
Пояснення:
TodoList.js
: відображає список завдань.TodoItem.js
: окремий компонент для кожного пункту.AddTodoForm.js
: компонент із формою додавання нового завдання.api.js
: модуль для взаємодії з API (запити та обробка помилок).App.js
: головний компонент, координує всі дії.
2. API (mock-варіант)
api.js – імітуємо роботу з сервером:
// api.js
const todos = [
{ id: 1, text: 'Вивчити React', completed: false },
{ id: 2, text: 'Прочитати статтю про Redux', completed: true },
];
// Імітація затримки
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
export async function getTodos() {
await delay(500); // імітація мережевої затримки
return todos;
}
export async function addTodo(text) {
await delay(300);
const newTodo = { id: Date.now(), text, completed: false };
todos.push(newTodo);
return newTodo;
}
export async function toggleTodo(id) {
await delay(200);
const todo = todos.find((t) => t.id === id);
if (todo) {
todo.completed = !todo.completed;
}
return todo;
}
export async function deleteTodo(id) {
await delay(200);
const index = todos.findIndex((t) => t.id === id);
if (index !== -1) {
todos.splice(index, 1);
}
return { success: true };
}
3. Головний компонент App.js
// App.js
import React, { useState, useEffect } from 'react';
import { getTodos, addTodo, toggleTodo, deleteTodo } from './api';
import TodoList from './components/TodoList';
import AddTodoForm from './components/AddTodoForm';
function App() {
const [todos, setTodos] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
async function fetchData() {
try {
const data = await getTodos();
setTodos(data);
} catch (err) {
setError('Не вдалося завантажити завдання');
} finally {
setLoading(false);
}
}
fetchData();
}, []);
const handleAddTodo = async (text) => {
try {
const newTodo = await addTodo(text);
setTodos((prev) => [...prev, newTodo]);
} catch (err) {
setError('Помилка при додаванні завдання');
}
};
const handleToggleTodo = async (id) => {
try {
const updated = await toggleTodo(id);
setTodos((prev) =>
prev.map((t) => (t.id === updated.id ? updated : t))
);
} catch (err) {
setError('Помилка при зміні статусу завдання');
}
};
const handleDeleteTodo = async (id) => {
try {
await deleteTodo(id);
setTodos((prev) => prev.filter((t) => t.id !== id));
} catch (err) {
setError('Помилка при видаленні завдання');
}
};
if (loading) return <p>Завантаження...</p>;
if (error) return <p>{error}</p>;
return (
<div>
<h1>Мій TODO-додаток</h1>
<AddTodoForm onAddTodo={handleAddTodo} />
<TodoList
todos={todos}
onToggle={handleToggleTodo}
onDelete={handleDeleteTodo}
/>
</div>
);
}
export default App;
Ключові моменти:
useEffect()
– завантаження списку завдань під час старту додатку.- Обробка помилок через
try/catch
. - Окремі функції для додавання, видалення та зміни статусу завдання.
4. Компонент AddTodoForm
// AddTodoForm.js
import React, { useState } from 'react';
function AddTodoForm({ onAddTodo }) {
const [text, setText] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
if (!text.trim()) return;
onAddTodo(text);
setText('');
};
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Нове завдання"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button type="submit">Додати</button>
</form>
);
}
export default AddTodoForm;
Що тут демонструє?
- Роботу з формою
- Роботу зі станом (text)
- Передачу callback
onAddTodo
5. Компонент TodoList і TodoItem
// TodoList.js
import React from 'react';
import TodoItem from './TodoItem';
function TodoList({ todos, onToggle, onDelete }) {
if (!todos.length) {
return <p>Завдань поки що немає</p>;
}
return (
<ul>
{todos.map((todo) => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={onToggle}
onDelete={onDelete}
/>
))}
</ul>
);
}
export default TodoList;
// TodoItem.js
import React from 'react';
function TodoItem({ todo, onToggle, onDelete }) {
return (
<li>
<input
type="checkbox"
checked={todo.completed}
onChange={() => onToggle(todo.id)}
/>
<span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
{todo.text}
</span>
<button onClick={() => onDelete(todo.id)}>Видалити</button>
</li>
);
}
export default TodoItem;
Що тут демонструє?
- Розділення логіки між компонентами
- Використання callback’ів для зміни стану (toggle, delete)
Чому таке завдання демонструє ключові навички?
- Робота зі станом (state management)
React-хуки (useState, useEffect) дають уявлення, як розробник керує станом. - Взаємодія з API
Показує, як обробляються асинхронні запити, помилки та завантаження. - Обробка подій
Форма додавання і чекбокси – класичні приклади. - Оптимізація
Хоча у прикладі немає складної оптимізації, але можна побачити, чи відокремлює розробник компоненти, аби уникати зайвих рендерів. - Обробка помилок
Наявністьtry/catch
для запитів до API. - Побудова UI
Використання простих компонентів (список, кнопки, поля вводу).
Можливі покращення та питання на співбесіді
- Сортування чи фільтрація
Додати функціонал сортування за станом (виконані/невиконані). - Валідація
Перед додаванням завдання можна перевіряти довжину тексту. - Оптимізація рендеру
Використання React.memo дляTodoItem
. - Тестування
Запитати, як кандидат писав би юніт-тести. - Альтернативні рішення (Redux, Context)
Як розподіляти логіку, якщо програма стає більшою?
Висновок
Одне завдання з TODO-додатком покриває багато аспектів React: від роботи зі станом і API до структурованого коду й обробки помилок. На співбесіді воно дає змогу швидко зрозуміти рівень кандидата, його підхід до архітектури та вміння справлятися з асинхронними сценаріями. Якщо ви готуєтесь до співбесіди – виконайте це завдання самостійно, а якщо ви інтерв’юер – задайте його кандидату та зверніть увагу на деталі реалізації.