React applications are built as a hierarchy of components. Some components sit higher in this hierarchy and render other components below them.
function App() {
return (
<div>
<h1>React</h1>
<p>Learning JSX</p>
</div>
);
}
A component that renders another component is commonly called the parent component.
The component being rendered is called the child component.
For example:
function Dashboard() {
return (
<main>
<Sidebar />
<CourseList />
</main>
);
}
Here, Dashboard is the parent component of Sidebar and CourseList.
The structure looks like this:
Dashboard
├── Sidebar
└── CourseList
Parent components play an important role in React because they often coordinate their child components, provide data through props, handle shared state, and respond to events coming from children.
Understanding parent components is essential before learning more advanced concepts such as lifting state up, Context, state management, and component communication.
What Is a Parent Component?
A parent component is a component that renders one or more other components.
For example:
function App() {
return (
<div>
<Header />
<MainContent />
<Footer />
</div>
);
}
In this example, App is the parent of:
HeaderMainContentFooter
The component hierarchy is:
App
├── Header
├── MainContent
└── Footer
The parent establishes the structure of the interface.
Parent and Child Relationships
Consider this example:
function CoursePage() {
return <CourseCard />;
}
Here:
CoursePage
└── CourseCard
CoursePage is the parent.
CourseCard is the child.
If CourseCard renders another component:
function CourseCard() {
return <CourseDetails />;
}
the hierarchy becomes:
CoursePage
└── CourseCard
└── CourseDetails
A component can therefore be both:
- A child of one component
- A parent of another component
For example, CourseCard is a child of CoursePage, but a parent of CourseDetails.
A Parent Can Render Multiple Children
A parent component can render multiple child components.
function Dashboard() {
return (
<main>
<WelcomeMessage />
<CourseList />
<ProgressCard />
<RecommendedCourses />
</main>
);
}
The structure becomes:
Dashboard
├── WelcomeMessage
├── CourseList
├── ProgressCard
└── RecommendedCourses
The parent does not need to contain the complete implementation of each child.
Instead, each child handles its own responsibility.
Parent Components Define Structure
One of the most common responsibilities of a parent component is organizing the structure of a page or feature.
For example:
function CourseDashboard() {
return (
<div className="dashboard">
<DashboardHeader />
<div className="dashboard-content">
<Sidebar />
<CourseList />
</div>
</div>
);
}
Here, CourseDashboard determines how the major sections fit together.
The children handle their individual responsibilities.
CourseDashboard
├── DashboardHeader
├── Sidebar
└── CourseList
This separation makes the code easier to maintain.
Parent Components Pass Data Through Props
One of the most important responsibilities a parent can have is passing data to a child.
For example:
function CoursePage() {
const courseTitle = "React Fundamentals";
return (
<CourseHeader title={courseTitle} />
);
}
The child receives the prop:
function CourseHeader({ title }) {
return <h1>{title}</h1>;
}
The data flow is:
Parent
↓
title prop
↓
Child
React’s data flow is primarily from parent to child.
Passing Multiple Props
A parent can pass multiple pieces of information.
function CoursePage() {
return (
<CourseCard
title="React Fundamentals"
instructor="Alex"
progress={70}
level="Beginner"
/>
);
}
The child receives them:
function CourseCard({
title,
instructor,
progress,
level
}) {
return (
<article>
<h2>{title}</h2>
<p>{instructor}</p>
<p>{progress}% complete</p>
<p>{level}</p>
</article>
);
}
The parent controls the data.
The child controls how that data is displayed.
Parent Components and State
Parent components often manage state that needs to be shared by multiple children.
For example:
import { useState } from "react";
function CourseDashboard() {
const [selectedCourse, setSelectedCourse] = useState(null);
return (
<main>
<CourseList
onSelectCourse={setSelectedCourse}
/>
<CourseDetails
course={selectedCourse}
/>
</main>
);
}
Here, the parent owns the state:
CourseDashboard
│
├── CourseList
│
└── CourseDetails
The parent can coordinate both children.
CourseList can tell the parent which course was selected.
CourseDetails can receive the selected course from the parent.
This pattern becomes especially important when sibling components need to communicate.
Sharing State Between Children
Suppose you have:
Dashboard
├── SearchBar
└── CourseList
The SearchBar changes the search term.
CourseList needs that search term to filter courses.
Instead of trying to send data directly from one sibling to another, the parent can manage the shared state.
function Dashboard() {
const [search, setSearch] = useState("");
return (
<>
<SearchBar
search={search}
onSearchChange={setSearch}
/>
<CourseList search={search} />
</>
);
}
The structure becomes:
Dashboard
/ \
↓ ↓
SearchBar CourseList
↑ ↑
└── state ─┘
This is an example of lifting state up.
The parent becomes the common place where shared state is stored.
Lifting State Up
When multiple child components need access to the same state, the state can often be moved to their closest common parent.
For example:
Before
SearchBar → search state
CourseList → needs search
Instead:
After
Dashboard
/ \
↓ ↓
SearchBar CourseList
↑ ↑
└─ shared state
The parent owns the state and passes the required values and callbacks to its children.
Example:
function Dashboard() {
const [search, setSearch] = useState("");
return (
<>
<SearchBar
value={search}
onChange={setSearch}
/>
<CourseList
search={search}
/>
</>
);
}
This creates predictable data flow.
Parent Components Can Pass Event Handlers
A parent can provide a function to a child through props.
For example:
function CoursePage() {
function handleEnroll() {
console.log("Course enrolled");
}
return (
<CourseActions
onEnroll={handleEnroll}
/>
);
}
The child receives the function:
function CourseActions({ onEnroll }) {
return (
<button onClick={onEnroll}>
Enroll Now
</button>
);
}
When the user clicks the button, the child calls the function supplied by the parent.
The flow is:
Parent
↓
passes callback
↓
Child
↓
user interaction
↓
callback executes
This allows children to communicate events back to their parent without directly changing the parent’s state.
Child-to-Parent Communication
React data normally flows downward through props.
However, a child can communicate an event or value upward by calling a callback function supplied by the parent.
For example:
function Parent() {
function handleMessage(message) {
console.log(message);
}
return (
<Child
onMessage={handleMessage}
/>
);
}
The child:
function Child({ onMessage }) {
return (
<button onClick={() => onMessage("Hello from Child")}>
Send Message
</button>
);
}
The child doesn’t directly modify the parent.
Instead, it calls the function provided by the parent.
This is a very common React communication pattern.
Parent Components and children
A parent can also provide flexible content through the children prop.
For example:
function Layout({ children }) {
return (
<div className="layout">
<Header />
<main>
{children}
</main>
<Footer />
</div>
);
}
Another component can provide the content:
function App() {
return (
<Layout>
<CoursePage />
</Layout>
);
}
Here, Layout acts as the parent structure for the content passed into it.
The hierarchy is conceptually:
Layout
├── Header
├── children
│ └── CoursePage
└── Footer
This pattern is especially useful for layouts, cards, modals, containers, and other wrapper components.
Parent Components and Reusable Children
Parent components often use the same child component multiple times.
For example:
function CourseList() {
return (
<section>
<CourseCard title="React" />
<CourseCard title="JavaScript" />
<CourseCard title="CSS" />
</section>
);
}
Here, CourseList is the parent and each CourseCard is a child.
CourseList
├── CourseCard
├── CourseCard
└── CourseCard
The parent controls the collection.
The child controls the individual card.
This separation is useful when building lists, tables, menus, product grids, course catalogs, and dashboards.
Parent Components and Lists
A parent can also generate child components from data.
const courses = [
{
id: 1,
title: "React Fundamentals"
},
{
id: 2,
title: "JavaScript Essentials"
},
{
id: 3,
title: "CSS Mastery"
}
];
Then:
function CourseList() {
return (
<section>
{courses.map((course) => (
<CourseCard
key={course.id}
title={course.title}
/>
))}
</section>
);
}
CourseList acts as the parent.
Each CourseCard is a child.
The parent uses the data to determine which children should be rendered.
Parent Components and Conditional Rendering
Parents can also determine whether children should be rendered.
For example:
function Dashboard({ isLoggedIn }) {
return (
<main>
{isLoggedIn ? (
<UserDashboard />
) : (
<Login />
)}
</main>
);
}
The parent decides which child component should appear.
If the user is logged in:
Dashboard
└── UserDashboard
Otherwise:
Dashboard
└── Login
This allows parent components to coordinate different parts of an application’s UI.
Parent Components and Layout
Some parent components primarily exist to organize layout.
For example:
function DashboardLayout({ children }) {
return (
<div className="dashboard-layout">
<Sidebar />
<main className="content">
{children}
</main>
</div>
);
}
The parent controls the overall layout.
The children provide the page-specific content.
This creates a clean separation between:
Layout responsibility
↓
DashboardLayout
Page responsibility
↓
Child content
Parent Components Do Not Automatically Control Everything
Being a parent does not mean the parent automatically controls every aspect of the child.
For example:
function Parent() {
return <Child />;
}
Child can still have its own state:
function Child() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
{count}
</button>
);
}
The child owns its own state.
A parent only needs to manage state when that state belongs at the parent level or needs to be shared with other components.
This is an important principle:
Keep state as close as possible to the components that need it, while moving it upward when sharing requires it.
Parent Components and State Ownership
Consider two components:
Dashboard
├── CourseList
└── CourseDetails
If only CourseList needs a piece of state, it can own that state.
function CourseList() {
const [selected, setSelected] = useState(null);
// ...
}
But if both CourseList and CourseDetails need that state, the parent may be a better owner:
function Dashboard() {
const [selected, setSelected] = useState(null);
return (
<>
<CourseList
selected={selected}
onSelect={setSelected}
/>
<CourseDetails
course={selected}
/>
</>
);
}
State ownership should follow the needs of the application.
Parent Components and Component Responsibility
A good parent component coordinates its children without taking over their responsibilities.
For example:
CourseDashboard
├── CourseHeader
├── CourseList
├── ProgressSummary
└── InstructorCard
CourseDashboard can coordinate the page.
CourseHeader handles the header.
CourseList handles the course list.
ProgressSummary handles progress.
InstructorCard handles instructor information.
The parent shouldn’t necessarily contain all of the implementation details of these components.
A Complete Example
Let’s build a small course dashboard.
First, create the parent:
import { useState } from "react";
function CourseDashboard() {
const [selectedCourse, setSelectedCourse] = useState(null);
return (
<main>
<CourseList
onSelectCourse={setSelectedCourse}
/>
<CourseDetails
course={selectedCourse}
/>
</main>
);
}
The course list receives a callback:
function CourseList({ onSelectCourse }) {
const courses = [
{
id: 1,
title: "React Fundamentals"
},
{
id: 2,
title: "JavaScript Essentials"
}
];
return (
<section>
{courses.map((course) => (
<CourseCard
key={course.id}
course={course}
onSelect={() => onSelectCourse(course)}
/>
))}
</section>
);
}
The card triggers the callback:
function CourseCard({ course, onSelect }) {
return (
<article>
<h2>{course.title}</h2>
<button onClick={onSelect}>
View Course
</button>
</article>
);
}
Finally, the details component receives the selected course:
function CourseDetails({ course }) {
if (!course) {
return <p>Select a course to view details.</p>;
}
return (
<section>
<h2>{course.title}</h2>
<p>Course details appear here.</p>
</section>
);
}
The complete relationship is:
CourseDashboard
├── CourseList
│ └── CourseCard
│
└── CourseDetails
CourseDashboard
│
└── owns selectedCourse state
│
┌──────┴──────┐
↓ ↓
CourseList CourseDetails
↓
CourseCard
This is a realistic example of how a parent can coordinate multiple child components.
Common Mistakes with Parent Components
Putting All Logic in the Parent
A parent shouldn’t become a giant component simply because it controls several children.
Keep child-specific responsibilities inside the child where appropriate.
Passing Every Piece of Data Down
Only pass props that a child actually needs.
Avoid unnecessary prop chains.
Keeping Shared State in the Wrong Component
If two sibling components need the same state, consider moving that state to their common parent.
Trying to Modify Child State Directly
A parent should not reach into a child’s internal state and change it directly.
Instead, design the data and event flow through props and callbacks.
Confusing Parent-Child Relationships with File Structure
A component being in a separate file does not make it a parent or child.
The relationship comes from the rendered component hierarchy.
For example:
function App() {
return <CourseCard />;
}
makes App the parent regardless of where the files are located.
Creating Unnecessary Parent Components
Not every wrapper needs to become a component.
Create a parent component when it provides meaningful structure, behavior, state, or composition.
Best Practices for Parent Components
Let Parents Coordinate
A parent is often a good place to coordinate related children.
Keep State at the Appropriate Level
Keep state local when possible.
Move it upward when multiple components need it.
Pass Data Down Through Props
Use clear props to provide children with the information they need.
Pass Events Through Callbacks
Children can notify parents by calling callback functions supplied through props.
Keep Children Focused
A parent should not absorb all of the responsibilities of its children.
Avoid Unnecessary Prop Drilling
If information must pass through many intermediate components that don’t use it, consider whether Context or another state-sharing approach would be more appropriate.
Image Placement
Place this image immediately after the section “Parent Components Pass Data Through Props.”
Create a modern 16:9 React infographic showing a parent component passing data and event handlers to child components.
The visual should show:
Parent
│
┌────────┴────────┐
↓ ↓
Child A Child B
↑
Props/Data
│
Callback
│
└──────→ Parent
Use a modern developer-focused UI with polished component cards, directional arrows, subtle React-inspired elements, and clean typography. Clearly communicate that data flows down through props while child interactions can trigger callbacks supplied by the parent.
Caption: Parent components provide data and callbacks to coordinate their child components.
Alt text: React parent component passing props and callback functions to child components.
Practice Exercise
Build a small learning dashboard with a parent component named Dashboard.
Create these child components:
Dashboard
├── SearchBar
├── CourseList
│ └── CourseCard
└── CourseDetails
The Dashboard should own the selected course:
const [selectedCourse, setSelectedCourse] = useState(null);
Pass a callback to CourseList:
<CourseList
onSelectCourse={setSelectedCourse}
/>
Then pass the selected course to CourseDetails:
<CourseDetails
course={selectedCourse}
/>
Your goal is to make the parent coordinate the children.
Try adding:
- Search functionality
- Course selection
- Course details
- A selected-course indicator
- A reusable
Button - A loading state
- An empty state when no course is selected
Pay attention to where each piece of state belongs.
Parent Components Cheat Sheet
| Concept | Meaning |
|---|---|
| Parent component | Component that renders another component |
| Child component | Component rendered by a parent |
| Props | Data passed from parent to child |
| Callback prop | Function passed from parent to child |
| State owner | Component responsible for managing a piece of state |
| Lifting state up | Moving shared state to a common parent |
children | Content passed inside a component |
| Component tree | Hierarchical structure of components |
A useful mental model is:
Parent
│
┌────────┴────────┐
↓ ↓
Child A Child B
│
↓
Grandchild
For data:
Parent
↓
Props
↓
Child
For events:
Parent
↓
Callback
↓
Child
↓
User interaction
↓
Callback executes
For shared state:
Common Parent
↓ ↓
Child A Child B
↑ ↑
Shared State
Key Takeaways
- A parent component is a component that renders one or more child components.
- Parent-child relationships are determined by the rendered component hierarchy.
- Parent components commonly organize application structure.
- Parents can pass data to children through props.
- Parents can pass event handlers to children through callback props.
- Children can communicate events back to parents by calling those callbacks.
- Shared state is often moved to the closest common parent.
- This technique is called lifting state up.
- A parent does not automatically own every piece of state used by its children.
- Keep state as close as practical to the components that need it.
- Parents should coordinate children without taking over their individual responsibilities.
- Avoid unnecessary prop drilling and unnecessary parent components.
- A well-designed parent component helps create predictable data flow and a maintainable component tree.
The core idea to remember is:
Parents organize and coordinate their children, while props and callbacks provide a predictable way for components to communicate.