“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)