ReactJS tutorial

Open ReactJS lesson pages →

Refactoring with prop Drilling

React prop Drilling

1

Study notes

Place shared state at the nearest common owner.

Read the explanation, run the worked example, then complete the matching Examples and Assignments tabs. Your original materials remain available alongside these notes.

Understand the idea

Refactoring should preserve behavior while splitting responsibilities. In your todo project, the parent owns tasks, the form reports a new title, and each row reports toggle or delete. In the ecommerce cart, the catalog reports a product and the cart reports a quantity change.

Prop drilling means passing a value through intermediate components. It is often a clear design for a short tree. If many distant components need the same data, context may simplify delivery, but it does not decide ownership for you. Keep a single authoritative cart and derive counts and totals from it.

Data / props ↓ JavaScript expression ↓ JSX elements ↓ Visible UI
Trace the values through each step before changing the code.

Run the example

Use a separate React practice project with a Node.js version supported by Vite. Create it once with these commands, then use its development URL. Do not paste this into the Edupoly website’s own source files.

npm create vite@latest react-practice -- --template react
cd react-practice
npm install
npm run dev

Replace src/App.jsx with the following complete example. Keep Vite’s generated src/main.jsx entry point.

src/App.jsx

import { useState } from 'react';
function Product({onAdd}) { return <button onClick={() => onAdd({id: 'book', name: 'Book', price: 100})}>Add book</button>; }
function Cart({items, onRemove}) { return <ul>{items.map(item => <li key={item.id}>{item.name}: {item.quantity}<button onClick={() => onRemove(item.id)}>Remove</button></li>)}</ul>; }
export default function App() {
  const [items, setItems] = useState([]);
  function add(product) {
    setItems(old => old.some(p => p.id === product.id)
      ? old.map(p => p.id === product.id ? {...p, quantity: p.quantity + 1} : p)
      : [...old, {...product, quantity: 1}]);
  }
  return <main><Product onAdd={add} /><Cart items={items} onRemove={id => setItems(old => old.filter(p => p.id !== id))} /><p>Total: ₹{items.reduce((sum, p) => sum + p.price * p.quantity, 0)}</p></main>;
}

Expected result

Two Add book clicks produce one cart row with quantity 2 and total ₹200; Remove empties the cart.

Apply this to your assignments

Refactor your existing todo and cart apps one component at a time. Add quantity decrement with a defined zero rule, then test that counts, prices and row removal remain consistent.

Your existing examples

  • Refactoring-child-parent-comm-project-todolist
  • Parent-child-comm-project-ecom-cart

Open the Examples tab to run or inspect these supplied projects. Their original links are preserved.

Open Assignments for your complete original worksheet and submission controls.

Common mistakes

Duplicating cart state in siblings causes disagreement. Avoid storing a total that can be computed from items.

Check your understanding

  1. Predict the output before running the example, then compare it with the result panel.
  2. Explain which value each expression reads and which action changes it.
  3. Try the boundary cases listed in the practice task and record what you observe.
  4. Rebuild one matching assignment without copying, then compare behavior with the original example.

Reference

Official documentation for this topic · Vite setup requirements