Turning Learners Into Developers
Codekilla
CODEKILLA
// projects.react

10 Best React JS Projects

Hand-picked and ordered easiest → hardest — each with complete code and expected output. Build these to turn lessons into a portfolio.

Back to React JS course
// solution.code
react
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom/client';

// Main Todo App Component
function TodoApp() {
  const [todos, setTodos] = useState([]);
  const [input, setInput] = useState('');

  // Load todos from localStorage on mount
  useEffect(() => {
    const saved = localStorage.getItem('todos');
    if (saved) setTodos(JSON.parse(saved));
  }, []);

  // Save todos to localStorage whenever they change
  useEffect(() => {
    localStorage.setItem('todos', JSON.stringify(todos));
  }, [todos]);

  // Add new todo
  const addTodo = () => {
    if (input.trim()) {
      setTodos([...todos, { id: Date.now(), text: input, completed: false }]);
      setInput('');
    }
  };

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

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

  return (
    <div style={{ padding: '20px', maxWidth: '500px', margin: '0 auto' }}>
      <h1>Todo List</h1>
      <div style={{ marginBottom: '20px' }}>
        <input
          value={input}
          onChange={(e) => setInput(e.target.value)}
          onKeyPress={(e) => e.key === 'Enter' && addTodo()}
          placeholder="Add a new todo..."
          style={{ padding: '8px', width: '70%' }}
        />
        <button onClick={addTodo} style={{ padding: '8px 16px', marginLeft: '10px' }}>Add</button>
      </div>
      <ul style={{ listStyle: 'none', padding: 0 }}>
        {todos.map(todo => (
          <li key={todo.id} style={{ marginBottom: '10px', display: 'flex', alignItems: 'center' }}>
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => toggleTodo(todo.id)}
            />
            <span style={{ 
              marginLeft: '10px', 
              textDecoration: todo.completed ? 'line-through' : 'none',
              flex: 1
            }}>{todo.text}</span>
            <button onClick={() => deleteTodo(todo.id)} style={{ padding: '4px 8px' }}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<TodoApp />);
output
A functional todo list interface is displayed with an input field and Add button at the top. Users can add todos by typing and clicking Add or pressing Enter. Each todo item shows a checkbox (to toggle completion with strikethrough effect), the todo text, and a Delete button. All data persists in browser localStorage, so refreshing the page maintains the todo list state.