▶️ Live demo

Try it yourself — interact with the example below.

Loading demo…

🎯 What Is Inverse Data Flow?

Imagine you want to add a new rule to your family's house:

WITHOUT INVERSE DATA FLOW (The Problem):
┌─────────────────────────────────────────┐
│  🏠 THE HOUSE (Your App)                │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │  👨‍👩‍👧 PARENT (Checkout Component)  │   │
│  │  "Family rules are posted here"   │   │
│  │                                   │   │
│  │  Rule: Bedtime is 9pm             │   │
│  │  (coupon state lives here)        │   │
│  └─────────────────────────────────┘   │
│              │              │            │
│              ▼              ▼            │
│  ┌─────────────┐    ┌─────────────┐   │
│  │  👶 Child   │    │  👶 Child   │   │
│  │ (Promotions)│    │  (Total)     │   │
│  │             │    │             │   │
│  │ "I want to  │    │ "I need to  │   │
│  │ add a new   │    │ read the    │   │
│  │ coupon!"    │    │ rules!"     │   │
│  │             │    │             │   │
│  │ But I can't │    │ Can read    │   │
│  │ change      │    │ rules ✓     │   │
│  │ parent's    │    │             │   │
│  │ rules! ✗    │    │             │   │
│  └─────────────┘    └─────────────┘   │
│                                         │
│  ❌ Child can't update parent's state!  │
│  ❌ One-way data flow blocks updates!   │
└─────────────────────────────────────────┘

WITH INVERSE DATA FLOW (The Solution):
┌─────────────────────────────────────────┐
│  🏠 THE HOUSE (Your App)                │
│                                         │
│  ┌─────────────────────────────────┐   │
│  │  👨‍👩‍👧 PARENT (Checkout Component)  │   │
│  │  "Family rules are posted here"   │   │
│  │                                   │   │
│  │  Rule: Bedtime is 9pm             │   │
│  │  + New coupon: SAVE20             │   │
│  │                                   │   │
│  │  📞 Parent gives child a          │   │
│  │     "phone" (setter function)     │   │
│  │     to call when rules change!    │   │
│  └─────────────────────────────────┘   │
│              │              │            │
│              ▼              ▼            │
│  ┌─────────────┐    ┌─────────────┐   │
│  │  👶 Child   │    │  👶 Child   │   │
│  │ (Promotions)│    │  (Total)     │   │
│  │             │    │             │   │
│  │ 📞 Uses    │    │ 📖 Reads    │   │
│  │ phone to   │    │ rules via   │   │
│  │ call parent│    │ props       │   │
│  │            │    │             │   │
│  │ "Hey Mom,  │    │ "Rules say  │   │
│  │ add SAVE20!"│   │ bedtime 9pm"│   │
│  │            │    │             │   │
│  │ Parent     │    │ Sees new    │   │
│  │ updates    │    │ coupon!     │   │
│  │ state! ✓   │    │     ✓       │   │
│  └─────────────┘    └─────────────┘   │
│                                         │
│  ✅ Child can ask parent to update!       │
│  ✅ Parent still owns the state!          │
│  ✅ Everyone sees the new data!          │
└─────────────────────────────────────────┘

THE INVERSE DATA FLOW DECISION FLOWCHART:
┌─────────────────────────────────────────┐
│  State lives in parent (lifted up)        │
│    ↓                                    │
│  Child needs to READ it?                  │
│    → Pass state down as prop ✓          │
│    ↓                                    │
│  Child needs to CHANGE it?                │
│    → Pass SETTER FUNCTION down as prop!   │
│    → Child calls the function!            │
│    → Parent's setter runs!                │
│    → Parent state updates!                │
│    → Parent re-renders!                   │
│    → New state flows down to all kids!  │
│    → Everyone in sync! ✓                  │
└─────────────────────────────────────────┘

⚠️ The Big Problem: "How Does a Child Update Parent State?"

// ==========================================
// THE "I CAN'T UPDATE PARENT" TRAP
// ==========================================

// ❌ WRONG: State in Promotions, Total can't see it,
// and even if we lift it, how does Promotions update it?

function BadCheckout() {
  return (
    <div className="checkout">
      <h1>Checkout</h1>
      <Promotions />    {/* Has coupon state? */}
      <Total />         {/* Needs coupon state! */}
      {/* Siblings! Can't share! */}
    </div>
  );
}

function Promotions() {
  // ❌ WRONG HOME: coupons state lives here!
  const [coupons, setCoupons] = useState([]);  // ← Trapped!
  const [inputValue, setInputValue] = useState("");

  function handleApply() {
    if (!inputValue) return;
    
    const newCoupon = { code: inputValue, discount: 20 };
    
    // We can add coupons here...
    setCoupons(prev => [...prev, newCoupon]);
    
    setInputValue("");
  }

  return (
    <div className="promotions">
      <h3>Apply Coupon</h3>
      <input 
        value={inputValue} 
        onChange={e => setInputValue(e.target.value)}
        placeholder="Enter code"
      />
      <button onClick={handleApply}>Apply</button>
      
      <div className="applied-coupons">
        {coupons.map(c => (
          <span key={c.code}>{c.code} (-${c.discount})</span>
        ))}
      </div>
    </div>
  );
}

function Total() {
  // ❌ Can't access coupons! Promotions won't share!
  // Total needs to calculate final price with discounts!
  
  const subtotal = 100;
  // const discount = coupons.reduce((s, c) => s + c.discount, 0); 
  // ^ ERROR! coupons is not defined!
  
  return (
    <div className="total">
      <h3>Order Total</h3>
      <p>Subtotal: ${100}</p>
      <p>Discount: ${0} ❌ Can't calculate!</p>
      <p>Total: ${100}</p>
    </div>
  );
}

// Problems:
// 1. Promotions owns coupons but Total needs them too!
// 2. They're siblings — can't pass props sideways!
// 3. Even if we lift state to Checkout, how does Promotions
//    update the state now that it lives in the parent?
// 4. Props are READ-ONLY! Children can't mutate props!
// 5. We need a way for child to tell parent: "Update this!"

// ==========================================
// THE SOLUTION: Pass the Setter Function Down!
// ==========================================

// ✅ CORRECT: State in parent, setter passed as prop!

function GoodCheckout() {
  // 🏠 HOME: Checkout (common parent of Promotions and Total)
  const [coupons, setCoupons] = useState([]);

  // Function to add coupons lives here too!
  function handleAddCoupon(newCoupon) {
    setCoupons(prev => [...prev, newCoupon]);
  }

  return (
    <div className="checkout">
      <h1>Checkout</h1>
      
      {/* Pass setter function down! This is the secret! */}
      <Promotions 
        coupons={coupons} 
        onAddCoupon={handleAddCoupon} 
      />
      
      {/* Pass state down to read! */}
      <Total coupons={coupons} />
    </div>
  );
}

function Promotions({ coupons, onAddCoupon }) {
  // Local state ONLY for the input!
  const [inputValue, setInputValue] = useState("");

  function handleApply() {
    if (!inputValue) return;
    
    const newCoupon = { code: inputValue, discount: 20 };
    
    // Call the parent's function!
    onAddCoupon(newCoupon);  // ← "Hey Checkout, add this coupon!"
    
    setInputValue("");
  }

  return (
    <div className="promotions">
      <h3>Apply Coupon</h3>
      <input 
        value={inputValue} 
        onChange={e => setInputValue(e.target.value)}
        placeholder="Enter code"
      />
      <button onClick={handleApply}>Apply</button>
      
      <div className="applied-coupons">
        {coupons.map(c => (
          <span key={c.code}>{c.code} (-${c.discount})</span>
        ))}
      </div>
    </div>
  );
}

function Total({ coupons }) {
  // Can now read coupons from props!
  const subtotal = 100;
  const discount = coupons.reduce((sum, c) => sum + c.discount, 0);
  const total = subtotal - discount;

  return (
    <div className="total">
      <h3>Order Total</h3>
      <p>Subtotal: ${subtotal}</p>
      <p>Discount: ${discount} ✅ Calculated from props!</p>
      <p>Total: ${total}</p>
    </div>
  );
}

// What happens when user applies "SAVE20":
// 
// 1. User types "SAVE20" in Promotions input
//    → Promotions' local inputValue state updates
//    → ONLY Promotions re-renders! ✓
//
// 2. User clicks "Apply" button
//    → Promotions' handleApply runs
//    → Creates newCoupon object
//    → Calls onAddCoupon(newCoupon) ← PROP FUNCTION!
//    → Checkout's handleAddCoupon runs
//    → Checkout's setCoupons updates state
//    → Checkout re-renders
//    → Promotions AND Total BOTH re-render
//    → Total now shows $20 discount! ✓
//    → Promotions shows "SAVE20" in list! ✓
//
// 3. The child asked parent to update!
//    → Parent updated its own state!
//    → New state flowed down to both children!
//    → Everyone sees the same data! ✓

📋 Complete Visual Examples

Create file: inverse-data-flow.js

// ==========================================
// INVERSE DATA FLOW - Complete Guide
// ==========================================

/*
THE INVERSE DATA FLOW DECISION FLOWCHART:
┌─────────────────────────────────────────┐
│  State needs to be shared by siblings?  │
│    ↓                                    │
│  Lift state to common parent!           │
│    ↓                                    │
│  Child needs to READ the state?         │
│    → Pass state as prop ✓               │
│    ↓                                    │
│  Child needs to CHANGE the state?         │
│    → Pass SETTER FUNCTION as prop!        │
│    → Child calls: onUpdate(newValue)      │
│    → Parent's function runs             │
│    → Parent calls: setState(newValue)     │
│    → React re-renders parent            │
│    → New state flows down to all kids   │
│    → Everyone in sync! ✓                │
└─────────────────────────────────────────┘

ONE-WAY vs INVERSE DATA FLOW:
┌─────────────────────────────────────────┐
│  ONE-WAY DATA FLOW (Normal)             │
│    • Parent → Child (always!)           │
│    • State flows DOWN via props           │
│    • Like water flowing downhill          │
│                                         │
│  INVERSE DATA FLOW (The "Trick")        │
│    • Child → Parent (via function call!)  │
│    • Function flows DOWN via props        │
│    • Child CALLS it → Parent UPDATES      │
│    • Like calling mom on the phone!       │
│                                         │
│  IMPORTANT: Data NEVER truly flows up!    │
│    • The FUNCTION flows down!             │
│    • The child USES the function!         │
│    • The parent owns the state!           │
└─────────────────────────────────────────┘
*/

// ==========================================
// EXAMPLE 1: Normal Data Flow (Parent → Child)
// ==========================================

import { useState } from 'react';

function Parent() {
  // 🏠 HOME: Parent owns the state
  const [message, setMessage] = useState("Hello!");

  return (
    <div>
      {/* Pass data DOWN to child */}
      <Child message={message} />  // ← "Here, read this!"
    </div>
  );
}

function Child({ message }) {
  // Child can READ the prop
  return <p>{message}</p>;  // ← "Thanks! I can read it!"
}

// Visual Flow:
// Parent: message = "Hello!"
//   ↓
// Child receives: message = "Hello!"
// Child displays: "Hello!"
//
// This is ONE-WAY data flow! ✓
// Data only moves DOWN!

// ==========================================
// EXAMPLE 2: The Problem (Child Can't Update)
// ==========================================

function BrokenParent() {
  const [count, setCount] = useState(0);

  return (
    <div>
      {/* We pass count down... */}
      <BrokenChild count={count} />
    </div>
  );
}

function BrokenChild({ count }) {
  // ❌ WRONG: Trying to update prop directly!
  // Props are READ-ONLY!
  
  return (
    <div>
      <p>Count: {count}</p>
      {/* This would be MUTATING a prop! FORBIDDEN! */}
      {/* <button onClick={() => count++}>+</button> */}
      {/* ERROR! Cannot assign to read-only property! */}
    </div>
  );
}

// Visual Flow:
// Parent: count = 0
//   ↓
// Child receives: count = 0
// Child wants to update: count = 1
//   ↑
// BLOCKED! Props are immutable!
// Child cannot change parent's state!
//
// This is the PROBLEM we need to solve!

// ==========================================
// EXAMPLE 3: Inverse Data Flow (The Solution)
// ==========================================

function FixedParent() {
  // 🏠 HOME: Parent owns the state
  const [count, setCount] = useState(0);

  // Function to update state lives here!
  function handleIncrement() {
    setCount(c => c + 1);
  }

  return (
    <div>
      {/* Pass BOTH data AND function down! */}
      <FixedChild 
        count={count}              // ← Data goes down
        onIncrement={handleIncrement}  // ← Function goes down!
      />
    </div>
  );
}

function FixedChild({ count, onIncrement }) {
  // Child can READ count
  // Child can CALL onIncrement to ask parent to update!
  
  return (
    <div>
      <p>Count: {count}</p>
      {/* Call the parent's function! */}
      <button onClick={onIncrement}>+1</button>  // ← "Hey parent, add 1!"
    </div>
  );
}

// Visual Flow:
// 1. Parent: count = 0
// 2. Parent passes count={0} and onIncrement={fn} down
// 3. Child receives both
// 4. User clicks "+1" button
// 5. Child calls onIncrement()  ← "Phone call to parent!"
// 6. Parent's handleIncrement runs
// 7. Parent's setCount updates state to 1
// 8. Parent re-renders
// 9. Parent passes count={1} down
// 10. Child re-renders with new count
// 11. Child displays: "Count: 1" ✓
//
// Key insight: The function flowed DOWN!
// The child USED it to trigger an update UP!
// This is "inverse" data flow! ✓

// ==========================================
// EXAMPLE 4: Complete Udemy Checkout
// ==========================================

// THE PROBLEM: Two siblings need coupons
// Promotions creates coupons
// Total reads coupons
// But siblings CANNOT pass props to each other!

// ❌ WRONG: State in Promotions, Total is blind!
function WrongCheckout() {
  return (
    <div>
      <Promotions />   {/* Has coupon state? */}
      <Total />        {/* Needs coupon state! */}
      {/* Can't share! Siblings! */}
    </div>
  );
}

// ✅ CORRECT: Lift state, pass setter down!
function CorrectCheckout() {
  // 🏠 HOME: Checkout (common parent)
  const [coupons, setCoupons] = useState([]);

  // Function to add coupons
  function handleAddCoupon(newCoupon) {
    setCoupons(prev => [...prev, newCoupon]);
  }

  // Function to remove coupons
  function handleRemoveCoupon(code) {
    setCoupons(prev => prev.filter(c => c.code !== code));
  }

  return (
    <div className="checkout">
      <h1>🛒 Checkout</h1>
      
      {/* Pass state AND setter function down! */}
      <Promotions 
        coupons={coupons}
        onAddCoupon={handleAddCoupon}
        onRemoveCoupon={handleRemoveCoupon}
      />
      
      {/* Pass state down to read! */}
      <Total coupons={coupons} />
    </div>
  );
}

// Promotions: Can ADD and REMOVE coupons
// It receives the functions and calls them!
function Promotions({ coupons, onAddCoupon, onRemoveCoupon }) {
  // Local state ONLY for the input!
  const [inputValue, setInputValue] = useState("");

  function handleApply(e) {
    e.preventDefault();
    if (!inputValue) return;

    const newCoupon = {
      code: inputValue,
      discount: Math.floor(Math.random() * 30) + 5
    };

    // Call parent's function!
    onAddCoupon(newCoupon);  // ← "Hey Checkout, add this!"
    
    setInputValue("");
  }

  return (
    <div className="promotions">
      <h3>🎟️ Apply Coupon</h3>
      <form onSubmit={handleApply}>
        <input
          value={inputValue}
          onChange={e => setInputValue(e.target.value)}
          placeholder="Enter coupon code"
        />
        <button>Apply</button>
      </form>

      <div className="coupon-list">
        <h4>Applied Coupons:</h4>
        {coupons.length === 0 ? (
          <p>No coupons applied</p>
        ) : (
          coupons.map(c => (
            <div key={c.code} className="coupon">
              <span>{c.code} (-${c.discount})</span>
              <button onClick={() => onRemoveCoupon(c.code)}>
                Remove
              </button>
            </div>
          ))
        )}
      </div>
    </div>
  );
}

// Total: Can READ coupons and calculate
function Total({ coupons }) {
  const subtotal = 100;
  
  // DERIVED STATE: Calculate from props!
  const discount = coupons.reduce((sum, c) => sum + c.discount, 0);
  const total = Math.max(0, subtotal - discount);

  return (
    <div className="total">
      <h3>💰 Order Summary</h3>
      <div className="line-item">
        <span>Subtotal:</span>
        <span>${subtotal}</span>
      </div>
      <div className="line-item" style={{ color: 'green' }}>
        <span>Discount:</span>
        <span>-${discount}</span>
      </div>
      <div className="line-item total-line">
        <span>Total:</span>
        <span>${total}</span>
      </div>
    </div>
  );
}

// Visual Flow of Inverse Data Flow:
// 1. Checkout owns coupons = []
// 2. Promotions receives onAddCoupon function
// 3. Total receives coupons array
// 4. User types "SAVE20" and clicks Apply
// 5. Promotions calls onAddCoupon({code: "SAVE20", discount: 20})
// 6. Checkout's handleAddCoupon runs
// 7. Checkout's setCoupons updates state
// 8. Checkout re-renders
// 9. Promotions AND Total BOTH re-render
// 10. Total shows discount: $20! ✓
// 11. Promotions shows "SAVE20" in list! ✓
//
// Why this works:
//    → Parent owns the "single source of truth"
//    → Child calls parent's function to update
//    → Parent updates → New data flows down
//    → All children see the update!

// ==========================================
// EXAMPLE 5: The Decision Flowchart in Code
// ==========================================

function DecisionFlowchartDemo() {
  // Question 1: Do we need to store data?
  // → YES! We need coupons

  // Question 2: Will it change?
  // → YES! User adds/removes coupons
  const [coupons, setCoupons] = useState([]);      // ← STATE! ✓

  // Question 3: Can it be derived?
  // → NO! User enters coupon codes

  // Question 4: Should updating re-render?
  // → YES! Total must show new price!

  // Question 5: Where should this live?
  // → Promotions needs to ADD coupons
  // → Total needs to READ coupons
  // → They are siblings! → LIFT TO CHECKOUT! ✓

  // Question 6: How does Promotions update it?
  // → Pass setter function down! → INVERSE DATA FLOW! ✓

  // Question 7: What about input value?
  // → Only Promotions needs it → LOCAL STATE! ✓
  const [inputValue, setInputValue] = useState("");

  // Question 8: What about total price?
  // → Derived from coupons → DERIVED STATE! ✓
  const discount = coupons.reduce((s, c) => s + c.discount, 0);

  return (
    <div>
      <Promotions coupons={coupons} setCoupons={setCoupons} />
      <Total discount={discount} />
    </div>
  );
}

// ==========================================
// EXAMPLE 6: Passing setState Directly vs Handler
// ==========================================

// Option A: Pass setState directly (shorter)
function ParentA() {
  const [items, setItems] = useState([]);

  return (
    <ChildA items={items} setItems={setItems} />  // ← Pass setter directly
  );
}

function ChildA({ items, setItems }) {
  function handleAdd() {
    setItems(prev => [...prev, "new item"]);  // ← Call setter directly
  }
  return <button onClick={handleAdd}>Add</button>;
}

// Option B: Pass handler function (recommended, more control)
function ParentB() {
  const [items, setItems] = useState([]);

  function handleAddItem(item) {               // ← Wrapper function
    setItems(prev => [...prev, item]);
  }

  return (
    <ChildB onAddItem={handleAddItem} />       // ← Pass handler
  );
}

function ChildB({ onAddItem }) {
  function handleClick() {
    onAddItem("new item");                      // ← Call handler
  }
  return <button onClick={handleClick}>Add</button>;
}

// Both work! But Option B is preferred because:
// 1. Parent controls HOW state updates
// 2. Child doesn't need to know about setItems
// 3. Easier to add validation in parent
// 4. More explicit about what child can do

🚀 Interactive React Usage Examples

Complete React File: InverseDataFlowMasterClass.jsx

import React, { useState } from 'react';

// ==========================================
// INTERACTIVE INVERSE DATA FLOW DEMO
// ==========================================

function InverseDataFlowMasterClass() {
  const [activeDemo, setActiveDemo] = useState('flowchart');

  const demos = {
    flowchart: { title: 'Decision Flowchart', component: <FlowchartDemo /> },
    oneway: { title: 'One-Way Flow', component: <OneWayFlowDemo /> },
    inverse: { title: 'Inverse Flow', component: <InverseFlowDemo /> },
    checkout: { title: 'Udemy Checkout', component: <CheckoutDemo /> },
    broken: { title: 'Broken (No Setter)', component: <BrokenSetterDemo /> }
  };

  return (
    <div style={{ maxWidth: '900px', margin: '0 auto', padding: '20px', fontFamily: 'Arial, sans-serif' }}>
      <header style={{ background: '#264653', color: 'white', padding: '30px', borderRadius: '10px', marginBottom: '30px' }}>
        <h1 style={{ margin: 0 }}>📞 Inverse Data Flow</h1>
        <p style={{ margin: '10px 0 0 0', opacity: 0.9 }}>Child-to-Parent Communication</p>
      </header>

      <nav style={{ display: 'flex', gap: '10px', marginBottom: '30px', flexWrap: 'wrap' }}>
        {Object.entries(demos).map(([key, { title }]) => (
          <button
            key={key}
            onClick={() => setActiveDemo(key)}
            style={{
              padding: '12px 24px',
              fontSize: '16px',
              border: 'none',
              borderRadius: '8px',
              cursor: 'pointer',
              backgroundColor: activeDemo === key ? '#e76f51' : '#e0e0e0',
              color: activeDemo === key ? 'white' : '#333',
              fontWeight: activeDemo === key ? 'bold' : 'normal'
            }}
          >
            {title}
          </button>
        ))}
      </nav>

      <main style={{ background: '#f8f9fa', padding: '30px', borderRadius: '10px', minHeight: '400px' }}>
        {demos[activeDemo].component}
      </main>
    </div>
  );
}

// ==========================================
// DEMO 1: The Decision Flowchart
// ==========================================

function FlowchartDemo() {
  const [step, setStep] = useState(1);

  const steps = [
    {
      num: 1,
      title: 'State in Parent?',
      question: 'Did you lift state to the common parent?',
      code: 'const [items, setItems] = useState([]); // In Parent',
      visual: '⬆️',
      desc: 'State must live in the parent first!'
    },
    {
      num: 2,
      title: 'Pass State Down',
      question: 'Does child need to READ the state?',
      code: '<Child items={items} /> // Pass data',
      visual: '⬇️',
      desc: 'Normal one-way data flow!'
    },
    {
      num: 3,
      title: 'Pass Function Down',
      question: 'Does child need to CHANGE the state?',
      code: '<Child onAdd={handleAdd} /> // Pass function',
      visual: '📞',
      desc: 'Pass the setter function as a prop!'
    },
    {
      num: 4,
      title: 'Child Calls Function',
      question: 'Child has an event (click, submit)?',
      code: 'onClick={() => onAdd(newItem)}',
      visual: '👆',
      desc: 'Child calls the function it received!'
    },
    {
      num: 5,
      title: 'Parent Updates',
      question: 'Parent function runs?',
      code: 'setItems(prev => [...prev, newItem]);',
      visual: '✅',
      desc: 'Parent updates its own state!'
    },
    {
      num: 6,
      title: 'Everyone Syncs!',
      question: 'New state flows down?',
      code: '// All children re-render with new data!',
      visual: '🔄',
      desc: 'React re-renders parent and all children!'
    }
  ];

  const current = steps[step - 1];

  return (
    <div>
      <h2>The Inverse Data Flow Flowchart 🧭</h2>

      <div style={{ display: 'flex', gap: '10px', marginBottom: '20px', justifyContent: 'center' }}>
        {steps.map(s => (
          <button
            key={s.num}
            onClick={() => setStep(s.num)}
            style={{
              width: '60px',
              height: '60px',
              borderRadius: '50%',
              border: 'none',
              cursor: 'pointer',
              background: step >= s.num ? '#e76f51' : '#e0e0e0',
              color: step >= s.num ? 'white' : '#333',
              fontSize: '24px',
              fontWeight: 'bold'
            }}
          >
            {s.num}
          </button>
        ))}
      </div>

      <div style={{ padding: '30px', background: 'white', borderRadius: '10px', border: '2px solid #264653' }}>
        <h3 style={{ color: '#264653', marginTop: 0 }}>Step {current.num}: {current.title}</h3>
        <p style={{ fontSize: '20px', color: '#555', fontWeight: 'bold' }}>{current.question}</p>

        <div style={{ display: 'grid', gap: '20px', gridTemplateColumns: '1fr 1fr', marginBottom: '20px' }}>
          <div>
            <pre style={{ 
              background: '#1e1e1e', 
              color: '#d4d4d4', 
              padding: '20px', 
              borderRadius: '8px',
              fontSize: '16px'
            }}>
              {current.code}
            </pre>
            <p style={{ fontSize: '18px', color: '#555' }}>{current.desc}</p>
          </div>
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: '80px' }}>
            {current.visual}
          </div>
        </div>
      </div>

      <div style={{ marginTop: '20px', padding: '15px', background: '#e8f5e9', borderRadius: '8px' }}>
        <h4>🧠 Memory Trick:</h4>
        <p>"You can't change your mom's rules, but you can call her on the phone and ask her to change them!"</p>
      </div>
    </div>
  );
}

// ==========================================
// DEMO 2: One-Way Data Flow
// ==========================================

function OneWayFlowDemo() {
  const [message, setMessage] = useState("Hello from Parent!");

  return (
    <div>
      <h2>One-Way Data Flow ⬇️</h2>

      <div style={{ marginBottom: '20px', padding: '15px', background: '#e3f2fd', borderRadius: '8px' }}>
        <h4>Data only flows from Parent to Child. Like water flowing downhill!</h4>
      </div>

      <div style={{ padding: '20px', background: '#264653', color: 'white', borderRadius: '10px', marginBottom: '20px' }}>
        <h3 style={{ margin: '0 0 10px 0' }}>👨‍👩‍👧 Parent Component</h3>
        <p style={{ margin: 0 }}>State: "{message}"</p>
        <button 
          onClick={() => setMessage("Updated by Parent!")}
          style={{ marginTop: '10px', padding: '8px 16px', background: '#e76f51', color: 'white', border: 'none', borderRadius: '5px' }}
        >
          Parent Updates
        </button>
      </div>

      <div style={{ padding: '20px', background: 'white', borderRadius: '10px', boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}>
        <h3 style={{ color: '#264653' }}>👶 Child Component</h3>
        <p style={{ color: '#666', fontSize: '14px' }}>Can only READ props!</p>
        <div style={{ padding: '20px', background: '#e3f2fd', borderRadius: '5px', fontSize: '20px' }}>
          Received: <strong>"{message}"</strong>
        </div>
        <p style={{ color: '#e76f51', marginTop: '10px' }}>
          ⚠️ Child cannot change this! Props are read-only!
        </p>
      </div>
    </div>
  );
}

// ==========================================
// DEMO 3: Inverse Data Flow
// ==========================================

function InverseFlowDemo() {
  const [count, setCount] = useState(0);

  function handleIncrement() {
    setCount(c => c + 1);
  }

  function handleDecrement() {
    setCount(c => c - 1);
  }

  return (
    <div>
      <h2>Inverse Data Flow 📞</h2>

      <div style={{ marginBottom: '20px', padding: '15px', background: '#e3f2fd', borderRadius: '8px' }}>
        <h4>Parent passes a FUNCTION down. Child calls it to update parent's state!</h4>
      </div>

      <div style={{ padding: '20px', background: '#264653', color: 'white', borderRadius: '10px', marginBottom: '20px', textAlign: 'center' }}>
        <h3 style={{ margin: '0 0 10px 0' }}>👨‍👩‍👧 Parent Component</h3>
        <p style={{ margin: 0, fontSize: '24px' }}>Count: {count}</p>
        <p style={{ margin: '10px 0 0 0', opacity: 0.8, fontSize: '14px' }}>I own this state!</p>
      </div>

      <div style={{ display: 'flex', gap: '20px', justifyContent: 'center' }}>
        <InverseChild 
          label="-1" 
          onClick={handleDecrement} 
          color="#e76f51"
        />
        <InverseChild 
          label="+1" 
          onClick={handleIncrement} 
          color="#2a9d8f"
        />
      </div>

      <div style={{ marginTop: '20px', padding: '15px', background: '#e8f5e9', borderRadius: '8px' }}>
        <h4>✅ How It Works:</h4>
        <ol>
          <li>Parent owns <code>count</code> state</li>
          <li>Parent creates <code>handleIncrement</code> function</li>
          <li>Parent passes <code>onClick={handleIncrement}</code> to Child</li>
          <li>Child receives the function as a prop</li>
          <li>Child calls <code>onClick()</code> when button is clicked</li>
          <li>Parent's function runs → Parent's state updates!</li>
          <li>Magic! ✨</li>
        </ol>
      </div>
    </div>
  );
}

function InverseChild({ label, onClick, color }) {
  return (
    <button
      onClick={onClick}
      style={{
        padding: '20px 40px',
        fontSize: '24px',
        background: color,
        color: 'white',
        border: 'none',
        borderRadius: '10px',
        cursor: 'pointer'
      }}
    >
      {label}
    </button>
  );
}

// ==========================================
// DEMO 4: Udemy Checkout
// ==========================================

function CheckoutDemo() {
  const [coupons, setCoupons] = useState([
    { code: 'WELCOME10', discount: 10 }
  ]);

  function handleAddCoupon(newCoupon) {
    setCoupons(prev => [...prev, newCoupon]);
  }

  function handleRemoveCoupon(code) {
    setCoupons(prev => prev.filter(c => c.code !== code));
  }

  const subtotal = 100;
  const discount = coupons.reduce((sum, c) => sum + c.discount, 0);
  const total = Math.max(0, subtotal - discount);

  return (
    <div>
      <h2>Udemy Checkout 🛒</h2>

      <div style={{ marginBottom: '20px', padding: '15px', background: '#e3f2fd', borderRadius: '8px' }}>
        <h4>Real-world example: Promotions adds coupons, Total calculates price!</h4>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '20px' }}>
        {/* Promotions */}
        <div style={{ padding: '20px', background: 'white', borderRadius: '10px', boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}>
          <h3 style={{ color: '#264653' }}>🎟️ Promotions</h3>
          <p style={{ color: '#666', fontSize: '14px' }}>Can ADD/REMOVE coupons</p>
          <CheckoutPromotions 
            coupons={coupons}
            onAddCoupon={handleAddCoupon}
            onRemoveCoupon={handleRemoveCoupon}
          />
        </div>

        {/* Total */}
        <div style={{ padding: '20px', background: 'white', borderRadius: '10px', boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}>
          <h3 style={{ color: '#264653' }}>💰 Total</h3>
          <p style={{ color: '#666', fontSize: '14px' }}>Can READ coupons</p>
          <CheckoutTotal subtotal={subtotal} discount={discount} total={total} />
        </div>
      </div>

      <div style={{ marginTop: '20px', padding: '15px', background: '#e8f5e9', borderRadius: '8px' }}>
        <h4>✅ How It Works:</h4>
        <ol>
          <li>Checkout owns <code>coupons</code> state</li>
          <li>Promotions receives <code>onAddCoupon</code> function</li>
          <li>Total receives <code>coupons</code> array (via derived values)</li>
          <li>User adds coupon → Promotions calls parent's function</li>
          <li>Checkout updates → Both children re-render!</li>
        </ol>
      </div>
    </div>
  );
}

function CheckoutPromotions({ coupons, onAddCoupon, onRemoveCoupon }) {
  const [inputValue, setInputValue] = useState("");

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

    onAddCoupon({
      code: inputValue,
      discount: Math.floor(Math.random() * 25) + 5
    });

    setInputValue("");
  }

  return (
    <div>
      <form onSubmit={handleSubmit} style={{ display: 'flex', gap: '10px', marginBottom: '15px' }}>
        <input
          value={inputValue}
          onChange={e => setInputValue(e.target.value)}
          placeholder="Enter code"
          style={{ padding: '10px', borderRadius: '5px', border: '1px solid #ddd', flex: 1 }}
        />
        <button style={{ padding: '10px 20px', background: '#2a9d8f', color: 'white', border: 'none', borderRadius: '5px' }}>
          Apply
        </button>
      </form>

      <div>
        {coupons.length === 0 ? (
          <p style={{ color: '#999' }}>No coupons</p>
        ) : (
          coupons.map(c => (
            <div key={c.code} style={{ display: 'flex', justifyContent: 'space-between', padding: '8px', background: '#e8f5e9', borderRadius: '5px', marginBottom: '5px' }}>
              <span>{c.code} (-${c.discount})</span>
              <button 
                onClick={() => onRemoveCoupon(c.code)}
                style={{ background: '#e76f51', color: 'white', border: 'none', borderRadius: '3px', cursor: 'pointer' }}
              >
                ✕
              </button>
            </div>
          ))
        )}
      </div>
    </div>
  );
}

function CheckoutTotal({ subtotal, discount, total }) {
  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', padding: '10px', borderBottom: '1px solid #eee' }}>
        <span>Subtotal</span>
        <span>${subtotal}</span>
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', padding: '10px', borderBottom: '1px solid #eee', color: '#2a9d8f' }}>
        <span>Discount</span>
        <span>-${discount}</span>
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', padding: '15px', fontWeight: 'bold', fontSize: '20px' }}>
        <span>Total</span>
        <span>${total}</span>
      </div>
    </div>
  );
}

// ==========================================
// DEMO 5: Broken (No Setter Passed)
// ==========================================

function BrokenSetterDemo() {
  const [showFix, setShowFix] = useState(false);

  return (
    <div>
      <h2>Broken: No Setter Passed ❌</h2>

      <div style={{ marginBottom: '20px', padding: '15px', background: '#ffebee', borderRadius: '8px' }}>
        <h4>Child tries to update state but has no function to call!</h4>
      </div>

      <div style={{ padding: '20px', background: 'white', borderRadius: '10px', boxShadow: '0 2px 10px rgba(0,0,0,0.1)' }}>
        <BrokenChildNoSetter />
      </div>

      <div style={{ marginTop: '20px', textAlign: 'center' }}>
        <button 
          onClick={() => setShowFix(!showFix)}
          style={{ padding: '10px 20px', background: '#264653', color: 'white', border: 'none', borderRadius: '5px' }}
        >
          {showFix ? 'Hide' : 'Show'} The Fix
        </button>
      </div>

      {showFix && (
        <div style={{ marginTop: '20px', padding: '20px', background: '#e8f5e9', borderRadius: '8px' }}>
          <h4 style={{ color: '#2e7d32' }}>✅ Fix: Pass the Setter!</h4>
          <pre style={{ background: '#1e1e1e', color: '#d4d4d4', padding: '15px', borderRadius: '4px' }}>
{`// Parent must pass the function!
<Child onUpdate={handleUpdate} />

// Child calls it!
<button onClick={() => onUpdate(newValue)}>
  Update
</button>`}
          </pre>
        </div>
      )}
    </div>
  );
}

function BrokenChildNoSetter() {
  // This child has NO way to update parent!
  // No onUpdate prop received!
  
  return (
    <div style={{ textAlign: 'center' }}>
      <p>😢 I want to update parent state...</p>
      <button 
        disabled
        style={{ padding: '10px 20px', background: '#ccc', color: '#666', border: 'none', borderRadius: '5px' }}
      >
        Can't Update (No Function!)
      </button>
    </div>
  );
}

export default InverseDataFlowMasterClass;

🧠 Memory Aids for Poor Logic Thinking

The "Phone Call to Mom" Analogy

┌─────────────────────────────────────────────────┐
│  INVERSE DATA FLOW = CALLING MOM ON THE PHONE    │
│                                                 │
│  Scenario: You want a later bedtime.            │
│                                                 │
│  ❌ WRONG WAY (Trying to change rules yourself): │
│  ┌──────────┐                                   │
│  │ Your Room│                                   │
│  │          │                                   │
│  │ "I want  │                                   │
│  │ bedtime  │                                   │
│  │ at 11pm!"│                                   │
│  │          │                                   │
│  │ *changes │                                   │
│  │  house   │                                   │
│  │  rules*  │                                   │
│  │          │                                   │
│  │ ❌ GROUNDED! You can't change parent's rules! │
│  └──────────┘                                   │
│                                                 │
│  ✅ CORRECT WAY (Calling mom):                   │
│  ┌──────────┐                                   │
│  │ Your Room│                                   │
│  │          │                                   │
│  │ 📞 "Hey  │                                   │
│  │  Mom, can│                                   │
│  │  I stay  │                                   │
│  │  up till │                                   │
│  │  11pm?"  │                                   │
│  │          │                                   │
│  │ (Calling │                                   │
│  │  onUpdate│                                   │
│  │  function│                                   │
│  │  prop)   │                                   │
│  └────┬─────┘                                   │
│       │                                         │
│       ▼                                         │
│  ┌─────────────────────────────────┐           │
│  │  👩 Mom (Parent Component)       │           │
│  │  "Let me think..."               │           │
│  │  setBedtime("11pm")              │           │
│  │  "Okay, new rule!"               │           │
│  │                                  │           │
│  │  Parent updates state!           │           │
│  │  New rule flows down to all kids!│           │
│  └─────────────────────────────────┘           │
│                                                 │
│  Key insight: You didn't change the rule!       │
│  You ASKED mom to change it!                    │
│  The phone (function) went from mom to you,     │
│  but the message went from you to mom!            │
└─────────────────────────────────────────────────┘

The "Restaurant Order" Analogy

┌─────────────────────────────────────────────────┐
│  INVERSE DATA FLOW = ORDERING AT A RESTAURANT    │
│                                                 │
│  You (Child) are at a restaurant table.          │
│  The Kitchen (Parent) cooks the food.            │
│                                                 │
│  ❌ WRONG WAY (Going to the kitchen yourself):   │
│  ┌──────────┐                                   │
│  │ You walk │                                   │
│  │ into the │                                   │
│  │ kitchen  │                                   │
│  │ and grab │                                   │
│  │ a burger!│                                   │
│  │          │                                   │
│  │ ❌ KICKED OUT!                               │
│  │ You can't touch the kitchen!                  │
│  │ (Can't mutate props!)                        │
│  └──────────┘                                   │
│                                                 │
│  ✅ CORRECT WAY (Using the waiter):              │
│  ┌──────────┐                                   │
│  │ You sit  │                                   │
│  │ at table │                                   │
│  │          │                                   │
│  │ 📝 Write │                                   │
│  │ order on │                                   │
│  │ paper    │                                   │
│  │ (call    │                                   │
│  │ onOrder) │                                   │
│  └────┬─────┘                                   │
│       │                                         │
│       ▼                                         │
│  ┌─────────────────────────────────┐           │
│  │  🏃 Waiter (Function Prop)       │           │
│  │  Takes order to kitchen          │           │
│  └─────────────────────────────────┘           │
│       │                                         │
│       ▼                                         │
│  ┌─────────────────────────────────┐           │
│  │  👨‍🍳 Kitchen (Parent)            │           │
│  │  Cooks the burger!                 │           │
│  │  setOrder(burger)                  │           │
│  │  Brings food back to you!          │           │
│  └─────────────────────────────────┘           │
│                                                 │
│  You didn't cook the burger!                     │
│  You asked the kitchen to cook it!              │
│  The waiter (function) carried your request!     │
└─────────────────────────────────────────────────┘

The "Bank Account" Analogy

┌─────────────────────────────────────────────────┐
│  INVERSE DATA FLOW = USING A DEBIT CARD         │
│                                                 │
│  Parent owns the bank account (state):           │
│  ┌─────────────────────────────────┐           │
│  │  🏦 BANK ACCOUNT (Parent State)  │           │
│  │  Balance: $500                     │           │
│  │  (Only parent can access directly) │           │
│  └─────────────────────────────────┘           │
│                                                 │
│  Parent gives child a DEBIT CARD:               │
│  ┌──────────┐                                   │
│  │ 👶 Child │                                   │
│  │          │                                   │
│  │ 💳 Debit │                                   │
│  │ Card     │                                   │
│  │ (onSpend │                                   │
│  │ function│                                   │
│  │ prop)    │                                   │
│  │          │                                   │
│  │ "I want  │                                   │
│  │ to buy   │                                   │
│  │ candy!"  │                                   │
│  └────┬─────┘                                   │
│       │                                         │
│       ▼                                         │
│  ┌─────────────────────────────────┐           │
│  │  💳 SWIPE! (Call function)     │           │
│  │  "Deduct $5 from account"        │           │
│  └─────────────────────────────────┘           │
│       │                                         │
│       ▼                                         │
│  ┌─────────────────────────────────┐           │
│  │  🏦 BANK ACCOUNT                 │           │
│  │  Balance: $495 (updated!)        │           │
│  │  Parent sees new balance!        │           │
│  └─────────────────────────────────┘           │
│                                                 │
│  Child didn't steal money!                       │
│  Child used the authorized card!                 │
│  Parent still controls the account!              │
│  But child can trigger updates!                  │
└─────────────────────────────────────────────────┘

The "Elevator" Analogy for Lifting + Inverse Flow

┌─────────────────────────────────────────────────┐
│  LIFTING + INVERSE FLOW = THE OFFICE BUILDING    │
│                                                 │
│  Imagine an office building:                     │
│                                                 │
│  ┌─────────────────────────────────────────┐   │
│  │  🏢 FLOOR 3: CEO Office (App)           │   │
│  │     "I own the company budget"            │   │
│  │     (State lives here)                    │   │
│  │                                           │   │
│  │     Gives managers PHONES:                │   │
│  │     "Call me if you need to spend money"  │   │
│  └─────────────────────────────────────────┘   │
│              │              │                    │
│              ▼              ▼                    │
│  ┌─────────────┐    ┌─────────────┐           │
│  │  Manager A  │    │  Manager B  │           │
│  │ (Promotions)│    │  (Total)    │           │
│  │             │    │             │           │
│  │ 📞 Has     │    │ 📖 Has     │           │
│  │ phone to   │    │ report to   │           │
│  │ call CEO   │    │ read budget │           │
│  │             │    │             │           │
│  │ "I need    │    │ "Budget is  │           │
│  │ $100 for   │    │ $1000"      │           │
│  │ marketing!" │    │             │           │
│  └──────┬──────┘    └─────────────┘           │
│         │                                       │
│         ▼                                       │
│  ┌─────────────────────────────────────────┐   │
│  │  📞 RING! Manager A calls CEO           │   │
│  │  "Approve $100 expense?"                  │   │
│  │  (Child calls parent's function!)       │   │
│  └─────────────────────────────────────────┘   │
│         │                                       │
│         ▼                                       │
│  ┌─────────────────────────────────────────┐   │
│  │  👔 CEO updates budget: $900 remaining   │   │
│  │  (Parent updates state!)                  │   │
│  │                                           │   │
│  │  Sends memo to ALL managers:              │   │
│  │  "New budget: $900"                       │   │
│  │  (Re-render with new props!)              │   │
│  └─────────────────────────────────────────┘   │
│                                                 │
│  Manager A spent money!                        │
│  Manager B sees the new budget!                │
│  Both stay in sync!                            │
│  CEO still owns the budget!                    │
└─────────────────────────────────────────────────┘

🎓 Practice Exercises

Exercise 1: Identify the Missing Piece

Look at this code. What's missing to make it work?

function Parent() {
  const [name, setName] = useState("");

  return (
    <div>
      <p>Parent knows: {name}</p>
      <Child />
    </div>
  );
}

function Child() {
  return (
    <input 
      placeholder="Enter name"
      // How do we update parent's state?
    />
  );
}

Questions:

  1. Does Child need to update Parent's state? → Yes!
  2. What does Parent need to pass to Child? → A function!
  3. What should Child do with the input? → Call the function!

Solution:

function Parent() {
  const [name, setName] = useState("");

  // Create the updater function!
  function handleNameChange(newName) {
    setName(newName);
  }

  return (
    <div>
      <p>Parent knows: {name}</p>
      {/* Pass the function down! */}
      <Child onNameChange={handleNameChange} />
    </div>
  );
}

function Child({ onNameChange }) {
  return (
    <input 
      placeholder="Enter name"
      onChange={(e) => onNameChange(e.target.value)}  // ← Call parent's function!
    />
  );
}

Exercise 2: Fix the Broken Checkout

This code has a bug. Promotions can't add coupons. Fix it!

// ❌ BROKEN: Setter not passed down!
function Checkout() {
  const [coupons, setCoupons] = useState([]);

  return (
    <div>
      <Promotions coupons={coupons} />
      <Total coupons={coupons} />
    </div>
  );
}

function Promotions({ coupons }) {
  const [input, setInput] = useState("");

  function handleApply() {
    // ❌ Can't call setCoupons! Not received!
    setCoupons(prev => [...prev, { code: input }]); // ERROR!
  }

  return (
    <div>
      <input value={input} onChange={e => setInput(e.target.value)} />
      <button onClick={handleApply}>Apply</button>
    </div>
  );
}

Solution:

// ✅ FIXED: Pass setter function down!
function Checkout() {
  const [coupons, setCoupons] = useState([]);

  // Create handler in parent!
  function handleAddCoupon(newCoupon) {
    setCoupons(prev => [...prev, newCoupon]);
  }

  return (
    <div>
      {/* Pass the function! */}
      <Promotions 
        coupons={coupons} 
        onAddCoupon={handleAddCoupon} 
      />
      <Total coupons={coupons} />
    </div>
  );
}

function Promotions({ coupons, onAddCoupon }) {
  const [input, setInput] = useState("");

  function handleApply() {
    // ✅ Call the parent's function!
    onAddCoupon({ code: input, discount: 10 });
    setInput("");
  }

  return (
    <div>
      <input value={input} onChange={e => setInput(e.target.value)} />
      <button onClick={handleApply}>Apply</button>
      <p>Applied: {coupons.length}</p>
    </div>
  );
}

Exercise 3: The Complete Decision Flowchart

You need to build a todo app. Walk through the flowchart:

Questions:

  1. Will todo data change? → Yes/No
  2. Can it be derived? → Yes/No
  3. Should it re-render? → Yes/No
  4. Where should it live?
  5. How does the form add todos?
  6. How does the list display todos?

Solution:

function TodoApp() {
  // 1. Does it change? → YES! (add/delete/toggle)
  // 2. Can it be derived? → NO! (user input)
  // 3. Should it re-render? → YES! (show new todos)
  // 4. Where? → TodoForm + TodoList are siblings
  //    → LIFT TO TODOAPP! ✓
  // 5. How does form add? → Pass onAddTodo function! ✓
  // 6. How does list display? → Pass todos array! ✓

  const [todos, setTodos] = useState([]);

  function handleAddTodo(text) {
    setTodos(prev => [...prev, { id: Date.now(), text, done: false }]);
  }

  function handleToggleTodo(id) {
    setTodos(prev => prev.map(t => 
      t.id === id ? { ...t, done: !t.done } : t
    ));
  }

  return (
    <div>
      <TodoForm onAddTodo={handleAddTodo} />
      <TodoList todos={todos} onToggleTodo={handleToggleTodo} />
    </div>
  );
}

function TodoForm({ onAddTodo }) {
  const [text, setText] = useState("");

  function handleSubmit(e) {
    e.preventDefault();
    if (!text) return;
    onAddTodo(text);  // ← Call parent's function!
    setText("");
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={text} onChange={e => setText(e.target.value)} />
      <button>Add</button>
    </form>
  );
}

function TodoList({ todos, onToggleTodo }) {
  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id} onClick={() => onToggleTodo(todo.id)}>
          <span style={{ textDecoration: todo.done ? 'line-through' : 'none' }}>
            {todo.text}
          </span>
        </li>
      ))}
    </ul>
  );
}

💡 Key Takeaways

ConceptWhat It MeansExample
One-Way Data FlowData only flows Parent → Child<Child message={msg} />
Inverse Data FlowChild calls parent's function to update<Child onUpdate={handleUpdate} />
Props are Read-OnlyChildren cannot change props directlyprops.count = 5 ❌ FORBIDDEN!
Setter FunctionThe function that updates statesetItems, setCoupons
Handler FunctionWrapper around setter (recommended)handleAddCoupon
Child-to-ParentCommunication patternChild calls function → Parent updates
Lifting State UpPrerequisite for inverse flowMove state to common parent first
Derived StateCalculate from lifted statediscount = coupons.reduce(...)

The Inverse Data Flow Pattern:

function InverseDataFlowPattern() {
  // Step 1: Lift state to common parent
  const [value, setValue] = useState("");
  
  // Step 2: Create handler function
  function handleUpdate(newValue) {
    setValue(newValue);
  }
  
  // Step 3: Pass state down to children that READ
  // Step 4: Pass handler down to children that WRITE
  return (
    <div>
      <Reader value={value} />
      <Writer onUpdate={handleUpdate} />
    </div>
  );
}

Golden Rules:

  1. Props are immutable — Never try to change a prop in a child!
  2. Pass the setter down — Give children a function to call!
  3. Parent owns the state — Only the parent calls useState!
  4. Child makes the request — Child calls the function, parent executes it!
  5. Data flows down, functions flow down, calls flow up — The function travels down, the execution travels up!
  6. Use handler functions — Don't pass setState directly, wrap it! (Better control)
  7. One source of truth — State lives in ONE component only!

One Sentence Summary:

> "Inverse data flow in React is the technique of passing an updater function from a parent component down to a child component as a prop so that when the child needs to modify state that lives in the parent, it can call that function which then executes in the parent scope and updates the parent's state, triggering a re-render that flows the new data back down to all children, enabling child-to-parent communication while maintaining React's one-way data flow architecture and ensuring props remain read-only!"