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)