šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

React: Component Communication

Learn how to pass data between parent and child components.

⚔ Total XP: 0|šŸ’» react XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

System Hub

Core logic.

Quick Quiz //

What is the primary danger of ignoring this concept?


šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

Every React component is its own isolated sandbox — it can't see a sibling's state or reach into its parent's variables. This lesson covers how components actually talk to each other anyway: props flowing down, callback functions flowing data back up, and lifting shared state to a common parent.

1The Sandbox Rule

By default, a React component is an isolated sandbox: it has no direct visibility into a parent's or sibling's variables and state. Data only flows one direction on its own — down from parent to child via props — so a child button click can't directly reach up and change something in its parent.

The workaround is that a parent can pass a function down as a prop. When the child calls that function (optionally with arguments as a payload), it's effectively sending data back up, since the function itself runs in the parent's scope and can update the parent's state.

āœ•
—
+
// Parent
<Child onAction={(data) => console.log(data)} />

// Child
<button onClick={() => props.onAction('Hello')}>Send</button>
localhost:3000

Component Isolation

2Step-by-Step Breakdown

The Sandbox Rule. In React, a component is like a walled sandbox. By default, it knows absolutely nothing about the components around it. Variables and state created inside a component CANNOT be directly seen by its parents or siblings.

Props: Flowing Down. You already know how data flows DOWN. A Parent component can pass data to a Child component using Props. This is a strict one-way street: Parent to Child.

The Upward Problem. But what if the Child has a button, and clicking that button needs to change the Parent's state? Props only flow down. You cannot pass props UP from a Child to a Parent.

Passing Callbacks Down. The solution is elegant: The Parent writes a FUNCTION that updates its own state. Then, the Parent passes THAT FUNCTION down to the Child as a prop!

To allow a Child to communicate with a Parent, what MUST the Parent pass down to the Child as a prop?

  • →A state variable
  • →A function (callback)

Executing the Callback. Now the Child has the function via its props. When an event occurs (like a button click) inside the Child, it simply EXECUTES the function it received. This triggers the code sitting up in the Parent!

The Payload (Data). The real magic: When the Child executes the callback function, it can pass ARGUMENTS into it! This is exactly how the Child sends DATA up to the Parent.

Receiving the Payload. Back in the Parent, the function we wrote receives that argument. The Parent can now use that data from the Child to update its own state!

If a Parent passes onSave={(data) => console.log(data)} to a Child, how does the Child send the string 'Saved!' up to the Parent?

  • →return
  • →props.onSave

Parent Updating State. The most common use case: A Child component (like an Input or a Form) sends data up to the Parent, and the Parent immediately takes that data and puts it into a setState function.

Sibling Communication. What if Sibling A needs to talk to Sibling B? They cannot communicate directly. Siblings do not have props to give each other. They only know about their Parent.

The Common Parent. To solve this, we find their closest common ancestor (their Parent). We move the shared state into the Parent. This is called 'Lifting State Up'.

Lifting State Up. The Parent holds the State. Sibling A gets a callback prop to update the State. Sibling B gets the State itself as a prop to display it. Now Sibling A controls Sibling B through the Parent!

If two sibling components need to share the exact same state, where MUST you declare that useState hook?

  • →In their common Parent
  • →In Sibling A

Communication Architect. Excellent! You now know how data flows around a React application. Props go down. Callbacks go down (and are executed upward). State is lifted to common ancestors when siblings need to share data.

Level Up šŸš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

Fully supported.

Accessibility (A11y)

1Callback-Driven Updates Still Need Accessible Feedback

When a child's callback causes the parent to update shared state (like a selected tab or an added item), make sure the resulting UI change is exposed to assistive technology — through focus management or an `aria-live` region — not just a visual re-render.

2Lifted State Should Keep Form Controls Properly Associated

When sibling inputs are lifted into a common parent's state, each control still needs its own `<label>` correctly linked via `htmlFor`/`id` — lifting state doesn't change what markup is required for the input itself to be accessible.

SEO Implications

  • 1

    Parent-Child Data Flow Has No Direct SEO Impact, but Rendered Output Does

    How a component internally passes callbacks or lifts state doesn't matter to a crawler — what matters is the final rendered HTML. Make sure interactions that reveal important content actually update the DOM in a way that's present when the page is indexed.

  • 2

    Avoid Architectures That Delay Critical Content Behind Deep Callback Chains

    If meaningful content only appears after several layers of callback-triggered state updates resolve on the client, it's more likely to be missed by crawlers that don't fully execute JavaScript or wait for late interactions.

Best Practices

Lift State Only as High as It Actually Needs to Go

Move shared state up to the closest common ancestor of the components that need it — hoisting it further than necessary forces unrelated components to re-render and makes the data flow harder to follow.

Name Callback Props for the Event, Not the Implementation

Prefer names like `onSave` or `onItemSelect` over `updateParentState` — the child shouldn't need to know or care what the parent actually does with the callback.

Frequent Bugs

THE BUG

A child component's button click doesn't seem to do anything in the parent.

THE FIX

The parent never passed a callback prop down, or the child called the prop incorrectly (e.g., invoking it immediately during render instead of inside an event handler). Pass a function as a prop and call it from within `onClick`.

THE BUG

Two sibling components display data that gets out of sync with each other.

THE FIX

Each sibling was holding its own local copy of what should be shared state. Lift the state up into their common parent and pass it down as props to both, so there's a single source of truth.

Real-World Examples

Search Box and Results List as Lifted-State Siblings

A search input and a results list are siblings that both need the current query. The common parent holds `query` in state, passes a callback down to the input to update it, and passes the current value down to the results list to filter by.

function SearchPage() {
  const [query, setQuery] = useState('');
  return (
    <>
      <SearchInput onSearch={setQuery} />
      <SearchResults query={query} />
    </>
  );
}

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Mutating State Directly

// Wrong const [user, setUser] = useState({ name: 'Alice' }); user.name = 'Bob'; // React won't re-render // Correct setUser({ ...user, name: 'Bob' });

The Solution //

Never mutate a state variable directly (e.g., state.count = 1). Always use the setter function provided by useState to ensure the component re-renders.

The Error //

Missing 'key' prop in lists

// Wrong {items.map(item => <li>{item.name}</li>)} // Correct {items.map(item => <li key={item.id}>{item.name}</li>)}

The Solution //

When rendering a list of elements using .map(), always provide a unique 'key' prop to the outermost element to help React identify which items have changed.

Continue Learning