“How do I even start building something in React?”
If you've asked yourself that question, you’re not alone. React can feel intimidating at first, but when you break it down one thought at a time, it becomes a superpower.
Let’s walk through building a To-Do App — not just the code, but the thinking process behind every line. This blog isn’t about copy-pasting; it’s about helping you develop a builder’s mindset.
🧠 Step 1: Think in Components
"What am I building?"
A To-Do App is a perfect starter project because it helps you practice:
- Displaying a list
- Adding new items
- Updating item state (like marking it done)
- Removing items
So let’s break it into components:
- App: The heart that holds everything.
- TodoList: Displays the list of items.
- TodoItem: Represents one task.
⚙️ Step 2: Set Up the Project
We’re using Vite for a fast and modern React setup.
npm create vite@latest react-todo-app -- --template react cd react-todo-app npm install npm run dev
Open src/App.jsx — that’s where your app lives.
📦 Step 3: Start from the Middle — The App.jsx
When I build something new, I don’t write everything at once. I start with what I understand best — in this case, managing the list of todos.
Here’s the code (with thought bubbles):
import { useState } from 'react'; import TodoList from './components/TodoList'; function App() { const [todos, setTodos] = useState([]); // 🧠 The to-do list const [text, setText] = useState(''); // ✍️ What the user is typing const addTodo = (e) => { e.preventDefault(); // ⛔ Prevent page refresh when form is submitted if (text.trim()) { const newTodo = { id: Date.now(), // Unique ID using current timestamp text, // The text the user typed completed: false // New tasks are not completed by default }; setTodos([...todos, newTodo]); // ✅ Add the new task to the existing list setText(''); // 🔄 Clear input field } }; // Toggle completion const toggleComplete = (id) => { setTodos(todos.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo )); }; // Delete a task const deleteTodo = (id) => { setTodos(todos.filter(todo => todo.id !== id)); }; return ( <div> <h1>React To-Do App</h1> {/* 🧠 Add a task */} <form onSubmit={addTodo}> <input type="text" value={text} placeholder="Add a new task" onChange={(e) => setText(e.target.value)} /> <button type="submit">Add</button> </form> {/* 🧠 Show the list */} <TodoList todos={todos} onToggle={toggleComplete} onDelete={deleteTodo} /> </div> ); } export default App;
🔍 What’s happening:
- The form is submitted → The addTodo function is called.
- If there's something typed (text.trim()), it creates a new todo object.
- The new task is added to the existing todos array using the spread operator.
- setText('') clears the input so the user can type the next task.
- Every task has a unique ID.
- In deleteTodo → filter() creates a new array excluding the task with the matching ID.
- The new filtered array is set back into the state using setTodos().
- map() goes through all tasks.
- In toggleComplete → when it finds the one with the matching ID, it flips the value of completed.
- The ...todo keeps everything else the same, only changing completed.
🔄 Step 4: Build TodoList & TodoItem
Why separate them?
Because every task can be reused, styled, or enhanced on its own. Keeping things modular = clean code.
TodoList.jsx
import TodoItem from './TodoItem'; function TodoList({ todos, onToggle, onDelete }) { return ( <ul> {todos.map(todo => ( <TodoItem key={todo.id} todo={todo} onToggle={onToggle} onDelete={onDelete} /> ))} </ul> ); } export default TodoList;
TodoItem.jsx
function TodoItem({ todo, onToggle, onDelete }) { return ( <li> <span onClick={() => onToggle(todo.id)} style={{ textDecoration: todo.completed ? 'line-through' : 'none', cursor: 'pointer', marginRight: '10px' }} > {todo.text} </span> <button onClick={() => onDelete(todo.id)}>❌</button> </li> ); } export default TodoItem;
🧩 Step 5: Test the Flow (and Think Like the User)
- Can I add a task?
- Can I mark it as done?
- Can I delete it?
- Does the app feel responsive and logical?
*If yes, congrats! You’ve just built your first real React app *🎉
🌱 Thought-Driven Dev Tips
- Don’t start with a blank screen — start with what makes sense to you.
- Build piece by piece. Get one feature working before adding the next.
- Keep asking: "What should happen when the user clicks here?"
- Think in state: “What changes in the app when I do something?”
Top comments (0)