DEV Community

Usama
Usama

Posted on

🚀 Mastering Child-to-Parent Communication in React (with Add, Delete & Toggle Example)

Have you ever wondered how a child component in React can send data or trigger actions in its parent? 🤔

That exact concept — child-to-parent communication — is one of the most important patterns every React developer needs to understand.

Today, I’ll walk you through how I built a small app called “Listo 🛒”, where users can add, delete, and toggle packed items, all powered by React’s state and props magic ✨


⚙️ Step 1: The State Lives in the Parent

In React, state should live where it’s needed the most.

Since multiple child components (Form, PackingList, Stats) need to access the same list of items, I kept the state in the parent App component.

function App() {
  const [items, setItems] = useState([]);
}
Enter fullscreen mode Exit fullscreen mode

Now App becomes the single source of truth for the data.


🧾 Step 2: Adding an Item (Child → Parent)

To add a new item, I created a function in the parent that updates the state:

function handleAddItem(item) {
  setItems((items) => [...items, item]);
}
Enter fullscreen mode Exit fullscreen mode

Then I passed this function down to the Form component as a prop:

<Form onAddItem={handleAddItem} />
Enter fullscreen mode Exit fullscreen mode

Inside the form, I created the new item and called the parent function:

function handleSubmit(e) {
  e.preventDefault();
  if (!description) return;

  const newItem = {
    description,
    quantity,
    unit,
    packed: false,
    id: Date.now(),
  };

  onAddItem(newItem);
}
Enter fullscreen mode Exit fullscreen mode

💡 Concept:
When the form submits, it doesn’t change state itself — it calls a function from the parent, sending data upward. That’s child-to-parent communication in action!


🗑️ Step 3: Deleting an Item

For delete, the logic again stays in the parent:

function handleDeleteItem(id) {
  setItems((items) => items.filter((item) => item.id !== id));
}
Enter fullscreen mode Exit fullscreen mode

And we pass it down to each Item component through props:

<button onClick={() => onDeleteItem(item.id)}></button>
Enter fullscreen mode Exit fullscreen mode

When the button is clicked, the child triggers the parent’s delete logic — clean and simple.


✅ Step 4: Toggling “Packed” Status

This part flips the packed value between true and false using the item’s id.

function handleTogglePacked(id) {
  setItems((items) =>
    items.map((item) =>
      item.id === id ? { ...item, packed: !item.packed } : item
    )
  );
}
Enter fullscreen mode Exit fullscreen mode

Then inside each Item:

<input
  type="checkbox"
  checked={item.packed}
  onChange={() => onTogglePacked(item.id)}
/>
Enter fullscreen mode Exit fullscreen mode

Now, clicking the checkbox updates the parent state instantly.
✅ No complex logic, just pure React reactivity.


🧠 What I Learned

This small app might look simple, but it teaches some of the core principles of React:

  • Keep state in the parent where multiple children can access it.
  • Pass functions as props to let children communicate back.
  • Always update state immutably (create new arrays/objects).

Once you understand this flow, everything in React — from forms to dashboards — becomes easier to reason about.


✨ Final Thoughts

Building “Listo 🛒” helped me finally connect theory with practice.
I used concepts like:
✅ Lifting state up
✅ Child-to-parent communication
✅ Controlled components

If you’re learning React, try this pattern in your own projects — it’ll solidify your understanding of how data flows in React. 💪

Top comments (0)