Module 2.4: Component Anatomy

🎯 Learning Objectives
Upon completing this lesson, you will be able to:
- Understand Function Components and why they are preferred.
- Pass data using Props from a Parent to a Child Component.
- Master the principle that Props are Read-only.
- Utilize Destructuring Props for cleaner code.
- Apply the Children Prop for the Composition pattern.
- Analyze UI Designs into a Component Hierarchy.
1. Function Component vs Class Component
1.1. Two Types of Components
React supports two ways to define components:

Function Component (Recommended):
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// Or using an Arrow Function
const Greeting = ({ name }) => {
return <h1>Hello, {name}!</h1>;
};Class Component (Legacy):
import { Component } from 'react';
class Greeting extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}1.2. Why Choose Function Components?
| Criterion | Function Component | Class Component |
|---|---|---|
| Syntax | Concise, easy to read | Verbose, complex |
| Hooks | ✅ Full support | ❌ No support |
this keyword | Not required | Must use this.props, this.state |
| Performance | Better (lighter) | Heavier |
| React Team | ✅ Recommended | ⚠️ Legacy |
💡 Key Takeaway: Since React 16.8+ (with Hooks), Function Components have become the standard. Class Components are now primarily found in older codebases.
1.3. Function Component Structure
// 1. Imports (if needed)
import { useState } from 'react';
// 2. Component Function
function ProductCard({ name, price, image }) {
// 3. Logic (hooks, variables, functions)
const formattedPrice = `$${price.toFixed(2)}`;
// 4. Return JSX
return (
<div className="product-card">
<img src={image} alt={name} />
<h3>{name}</h3>
<p>{formattedPrice}</p>
</div>
);
}
// 5. Export
export default ProductCard;2. Props - Passing Data
2.1. What are Props?
Props (Properties) are how you pass data from a Parent Component to a Child Component.

// Parent Component
function App() {
return (
<div>
<UserCard name="Alice" age={25} isActive={true} />
<UserCard name="Bob" age={30} isActive={false} />
</div>
);
}
// Child Component
function UserCard({ name, age, isActive }) {
return (
<div className="user-card">
<h2>{name}</h2>
<p>Age: {age}</p>
<span>{isActive ? '🟢 Active' : '🔴 Inactive'}</span>
</div>
);
}2.2. Prop Data Types
<Component
// String
title="Hello World"
// Number
count={42}
price={99.99}
// Boolean
isVisible={true}
disabled={false}
// Array
items={['Apple', 'Banana', 'Orange']}
// Object
user={{ name: 'Alice', email: 'alice@example.com' }}
// Function
onClick={() => console.log('Clicked!')}
onSubmit={handleSubmit}
// JSX / Component
icon={<StarIcon />}
/>2.3. The Props Object
All props are bundled into a single object:
function UserCard(props) {
console.log(props);
// { name: "Alice", age: 25, isActive: true }
return (
<div>
<h2>{props.name}</h2>
<p>Age: {props.age}</p>
</div>
);
}3. Props Are Read-Only
3.1. The Immutability Principle
Props cannot be modified inside a component. This embodies React’s one-way data flow principle.
// ❌ INCORRECT - Do not modify props directly
function UserCard({ name }) {
name = name.toUpperCase(); // Error!
return <h2>{name}</h2>;
}
// ✅ CORRECT - Create a new variable from props
function UserCard({ name }) {
const displayName = name.toUpperCase();
return <h2>{displayName}</h2>;
}3.2. Why Should Props Be Immutable?
| Reason | Explanation |
|---|---|
| Predictable | A component always renders consistently with the same props. |
| Debugging | Easy to track data flow from parent to child. |
| Performance | React compares props to decide whether to re-render. |
| Unidirectional | Data flows in one direction only: Parent → Child. |
3.3. What If You Need to Change Data?
If you need to change data, use State (which we’ll cover in a later module):
// Parent manages state, passes it down to child via props
function App() {
const [count, setCount] = useState(0);
return <Counter value={count} onIncrement={() => setCount(count + 1)} />;
}
function Counter({ value, onIncrement }) {
return (
<div>
<p>Count: {value}</p>
<button onClick={onIncrement}>+1</button>
</div>
);
}4. Destructuring Props
4.1. In Function Parameters
The most common approach is to destructure directly within the function parameter:
// ❌ Without destructuring - you have to write props.xxx multiple times
function UserCard(props) {
return (
<div>
<h2>{props.name}</h2>
<p>{props.email}</p>
</div>
);
}
// ✅ Destructure in the parameter - cleaner
function UserCard({ name, email }) {
return (
<div>
<h2>{name}</h2>
<p>{email}</p>
</div>
);
}4.2. Default Values
Set default values when props are not passed:
function Button({ label = 'Click me', variant = 'primary', size = 'medium', disabled = false }) {
return (
<button className={`btn btn-${variant} btn-${size}`} disabled={disabled}>
{label}
</button>
);
}// Usage
<Button /> // Uses all defaults
<Button label="Submit" /> // Overrides label
<Button variant="danger" size="lg"/> // Overrides variant & size4.3. Rest Props
Capture remaining props using the spread operator:
function Input({ label, error, ...rest }) {
return (
<div className="input-group">
<label>{label}</label>
<input {...rest} />
{error && <span className="error">{error}</span>}
</div>
);
}
// Usage - type, placeholder, and onChange are passed to the <input /> element
<Input label="Email" type="email" placeholder="Enter email" onChange={handleChange} error={errors.email} />;5. The Children Prop
5.1. What is Children?
children is a special prop that holds the content between a component’s opening and closing tags:
// Parent passes children
<Card>
<h2>Title</h2>
<p>Content goes here</p>
</Card>;
// Card component receives children
function Card({ children }) {
return <div className="card">{children}</div>;
}5.2. Composition Pattern

// Layout Component
function PageLayout({ children }) {
return (
<div className="page">
<Header />
<main className="content">{children}</main>
<Footer />
</div>
);
}
// Usage
function HomePage() {
return (
<PageLayout>
<h1>Welcome</h1>
<p>This is the home page content.</p>
<ProductList />
</PageLayout>
);
}5.3. Example: Modal Component
function Modal({ isOpen, onClose, title, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal" onClick={(e) => e.stopPropagation()}>
<div className="modal-header">
<h2>{title}</h2>
<button onClick={onClose}>×</button>
</div>
<div className="modal-body">{children}</div>
</div>
</div>
);
}
// Usage
<Modal isOpen={showModal} onClose={() => setShowModal(false)} title="Confirm">
<p>Are you sure you want to delete this item?</p>
<button onClick={handleDelete}>Delete</button>
<button onClick={() => setShowModal(false)}>Cancel</button>
</Modal>;6. Product Mindset: Design → Components
6.1. Analyzing the UI
When you receive a design, here’s the mindset process:
- Look at the big picture → Identify the main layout
- Break it down → Find repeatable sections
- Name them → Give your components meaningful names
- Determine props → Identify what data needs to be passed in
6.2. Example: Product Card UI
Let’s say you have a design like this:

Step 1: Identify Components
ProductCard
├── ProductImage
├── ProductInfo
│ ├── ProductName
│ ├── Rating
│ └── Price
└── AddToCartButtonStep 2: Determine Props
// What data does ProductCard need?
interface ProductCardProps {
id: string;
name: string;
image: string;
rating: number;
reviewCount: number;
price: number;
originalPrice?: number;
onAddToCart: (id: string) => void;
}Step 3: Implement
function ProductCard({ id, name, image, rating, reviewCount, price, originalPrice, onAddToCart }) {
return (
<div className="product-card">
<img src={image} alt={name} className="product-image" />
<div className="product-info">
<h3 className="product-name">{name}</h3>
<Rating value={rating} count={reviewCount} />
<Price current={price} original={originalPrice} />
</div>
<button onClick={() => onAddToCart(id)}>Add to Cart</button>
</div>
);
}6.3. Component Hierarchy
