> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 02. Components & Props

> Learn about Functional Components, Props, and Component Composition patterns.

# Components & Props

Components are the building blocks of any React application. They let you split the UI into independent, reusable pieces, and think about each piece in isolation.

**The LEGO analogy**: A LEGO set gives you individual bricks (components) that each serve a purpose -- a window block, a roof tile, a door. You can combine them to build a house, rearrange them to build a spaceship, or reuse the same window block in both. React components work the same way: a `Button`, a `Header`, a `Card` -- each is self-contained, reusable, and composable. The difference is that React components can accept data (props) that change how they look and behave, like a LEGO brick that changes color based on what you tell it.

## Component Mental Model

Think of components like LEGO blocks:

```
┌─────────────────────────────────────────────────────────────────┐
│                         App Component                           │
├─────────────────────────────────────────────────────────────────┤
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    Header Component                      │   │
│  │  ┌──────────────┐  ┌──────────────────────────────────┐ │   │
│  │  │    Logo      │  │         Navigation               │ │   │
│  │  └──────────────┘  └──────────────────────────────────┘ │   │
│  └─────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                     Main Content                         │   │
│  │  ┌─────────────────┐  ┌─────────────────────────────┐   │   │
│  │  │   ProductCard   │  │        ProductCard          │   │   │
│  │  └─────────────────┘  └─────────────────────────────┘   │   │
│  └─────────────────────────────────────────────────────────┘   │
│  ┌─────────────────────────────────────────────────────────┐   │
│  │                    Footer Component                      │   │
│  └─────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────┘
```

## Functional Components

In modern React, we primarily use **Functional Components**. They are simply JavaScript functions that return JSX.

```javascript theme={null}
// Function Declaration
function Welcome() {
  return <h1>Hello, World</h1>;
}

// Arrow Function (more common)
const Welcome = () => {
  return <h1>Hello, World</h1>;
};

// Arrow Function with implicit return
const Welcome = () => <h1>Hello, World</h1>;
```

### Component Naming Rules

<Warning>
  Component names **must start with a capital letter**. React treats lowercase elements as HTML tags.

  ```javascript theme={null}
  // ❌ Wrong - React treats this as an HTML tag
  const welcome = () => <h1>Hi</h1>;
  <welcome /> // Renders as <welcome></welcome>

  // ✅ Correct
  const Welcome = () => <h1>Hi</h1>;
  <Welcome /> // Renders the component
  ```
</Warning>

### Importing and Exporting Components

```javascript theme={null}
// Welcome.jsx - Named export
export const Welcome = () => <h1>Hello</h1>;

// Welcome.jsx - Default export
const Welcome = () => <h1>Hello</h1>;
export default Welcome;

// App.jsx - Importing
import Welcome from './Welcome';           // Default import
import { Welcome } from './Welcome';       // Named import
import { Welcome as Greeting } from './Welcome'; // Renamed import
```

***

## Props (Properties)

Props are the way to pass data from parent to child components. Think of them as function arguments -- because that is literally what they are. A React component is a function, and props are its parameters. Just like you would call `greet("Alice")` to pass a name to a function, you write `<Welcome name="Alice" />` to pass a name to a component.

### Passing Props

```javascript theme={null}
function App() {
  return (
    <div>
      <Welcome name="Sara" age={25} isOnline={true} />
      <Welcome name="Bob" age={30} isOnline={false} />
    </div>
  );
}
```

### Receiving Props

The component receives all props as a single object.

```javascript theme={null}
// Method 1: Props object
function Welcome(props) {
  return (
    <h1>
      Hello, {props.name}. You are {props.age} years old.
      {props.isOnline && <span> 🟢</span>}
    </h1>
  );
}

// Method 2: Destructuring (recommended)
function Welcome({ name, age, isOnline }) {
  return (
    <h1>
      Hello, {name}. You are {age} years old.
      {isOnline && <span> 🟢</span>}
    </h1>
  );
}
```

### Props Are Read-Only (Immutable)

<Warning>
  **Never modify props!** Props are read-only. Attempting to change them violates React's core principles.

  ```javascript theme={null}
  // ❌ NEVER do this
  function BadComponent(props) {
    props.name = 'Changed'; // ERROR!
    return <h1>{props.name}</h1>;
  }

  // ✅ If you need to modify data, use state (covered in next chapter)
  ```
</Warning>

***

## Default Props

You can provide default values for props when they're not passed.

```javascript theme={null}
// Method 1: Default parameters (recommended)
function Button({ color = 'blue', size = 'medium', text }) {
  return (
    <button 
      style={{ backgroundColor: color }}
      className={`btn-${size}`}
    >
      {text}
    </button>
  );
}

// Method 2: defaultProps (older approach)
function Button({ color, size, text }) {
  // ...
}
Button.defaultProps = {
  color: 'blue',
  size: 'medium'
};
```

***

## Children Prop

`children` is a special prop that allows you to pass components or content *between* the opening and closing tags.

```javascript theme={null}
function Card({ children, title }) {
  return (
    <div className="card">
      <h2 className="card-title">{title}</h2>
      <div className="card-body">
        {children}
      </div>
    </div>
  );
}

function App() {
  return (
    <Card title="Welcome">
      <p>This is the card content.</p>
      <button>Click me</button>
    </Card>
  );
}
```

### Practical Children Patterns

```javascript theme={null}
// Layout component
function PageLayout({ children }) {
  return (
    <div className="page">
      <Header />
      <main>{children}</main>
      <Footer />
    </div>
  );
}

// Modal component
function Modal({ children, isOpen, onClose }) {
  if (!isOpen) return null;
  
  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="modal-content" onClick={e => e.stopPropagation()}>
        {children}
      </div>
    </div>
  );
}

// Usage
<Modal isOpen={showModal} onClose={() => setShowModal(false)}>
  <h2>Confirm Action</h2>
  <p>Are you sure you want to proceed?</p>
  <button onClick={handleConfirm}>Yes</button>
</Modal>
```

***

## Prop Types (Runtime Validation)

PropTypes provide runtime type checking for your components.

```bash theme={null}
npm install prop-types
```

```javascript theme={null}
import PropTypes from 'prop-types';

function UserCard({ name, age, email, isAdmin, avatar }) {
  return (
    <div className="user-card">
      <img src={avatar} alt={name} />
      <h2>{name}</h2>
      <p>Age: {age}</p>
      <p>Email: {email}</p>
      {isAdmin && <span className="badge">Admin</span>}
    </div>
  );
}

UserCard.propTypes = {
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
  email: PropTypes.string.isRequired,
  isAdmin: PropTypes.bool,
  avatar: PropTypes.string
};

UserCard.defaultProps = {
  isAdmin: false,
  avatar: '/default-avatar.png'
};
```

### Common PropTypes

| PropType                                      | Description                                   |
| --------------------------------------------- | --------------------------------------------- |
| `PropTypes.string`                            | String value                                  |
| `PropTypes.number`                            | Number value                                  |
| `PropTypes.bool`                              | Boolean value                                 |
| `PropTypes.array`                             | Array                                         |
| `PropTypes.object`                            | Object                                        |
| `PropTypes.func`                              | Function                                      |
| `PropTypes.node`                              | Anything renderable (string, number, element) |
| `PropTypes.element`                           | React element                                 |
| `PropTypes.oneOf(['a', 'b'])`                 | One of specific values                        |
| `PropTypes.arrayOf(PropTypes.number)`         | Array of specific type                        |
| `PropTypes.shape({ name: PropTypes.string })` | Object with specific shape                    |

<Tip>
  For production apps, consider using **TypeScript** instead of PropTypes. It provides compile-time checking and better IDE support.
</Tip>

***

## Component Composition Patterns

### 1. Container and Presentational Components

Separate logic from presentation:

```javascript theme={null}
// Presentational Component (dumb) - only handles display
function UserList({ users, onSelect }) {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id} onClick={() => onSelect(user)}>
          {user.name}
        </li>
      ))}
    </ul>
  );
}

// Container Component (smart) - handles logic
function UserListContainer() {
  const [users, setUsers] = useState([]);
  const [selectedUser, setSelectedUser] = useState(null);

  useEffect(() => {
    fetch('/api/users')
      .then(res => res.json())
      .then(setUsers);
  }, []);

  return <UserList users={users} onSelect={setSelectedUser} />;
}
```

### 2. Compound Components

Components that work together to form a complete UI:

```javascript theme={null}
// Accordion compound component
function Accordion({ children }) {
  const [openIndex, setOpenIndex] = useState(null);
  
  return (
    <div className="accordion">
      {React.Children.map(children, (child, index) =>
        React.cloneElement(child, {
          isOpen: index === openIndex,
          onToggle: () => setOpenIndex(index === openIndex ? null : index)
        })
      )}
    </div>
  );
}

function AccordionItem({ title, children, isOpen, onToggle }) {
  return (
    <div className="accordion-item">
      <button onClick={onToggle} className="accordion-header">
        {title}
        <span>{isOpen ? '−' : '+'}</span>
      </button>
      {isOpen && <div className="accordion-content">{children}</div>}
    </div>
  );
}

// Usage
<Accordion>
  <AccordionItem title="Section 1">Content 1</AccordionItem>
  <AccordionItem title="Section 2">Content 2</AccordionItem>
  <AccordionItem title="Section 3">Content 3</AccordionItem>
</Accordion>
```

### 3. Render Props

Pass a function as a child to share logic:

```javascript theme={null}
function MouseTracker({ children }) {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  useEffect(() => {
    const handleMove = (e) => setPosition({ x: e.clientX, y: e.clientY });
    window.addEventListener('mousemove', handleMove);
    return () => window.removeEventListener('mousemove', handleMove);
  }, []);

  return children(position);
}

// Usage
<MouseTracker>
  {({ x, y }) => (
    <div>Mouse position: {x}, {y}</div>
  )}
</MouseTracker>
```

***

## Spreading Props

You can spread all props to a child component:

```javascript theme={null}
function Button({ className, children, ...rest }) {
  return (
    <button className={`btn ${className}`} {...rest}>
      {children}
    </button>
  );
}

// All native button props (onClick, disabled, type, etc.) are passed through
<Button 
  className="primary" 
  onClick={handleClick} 
  disabled={isLoading}
  type="submit"
>
  Submit
</Button>
```

***

## 🎯 Practice Exercises

<Accordion title="Exercise 1: Create a Reusable Alert Component">
  Build an `Alert` component that accepts:

  * `type`: 'success' | 'warning' | 'error'
  * `title`: string
  * `children`: content

  ```javascript theme={null}
  function Alert({ type = 'info', title, children }) {
    const styles = {
      success: { bg: '#d1fae5', border: '#10b981', color: '#065f46' },
      warning: { bg: '#fef3c7', border: '#f59e0b', color: '#92400e' },
      error: { bg: '#fee2e2', border: '#ef4444', color: '#991b1b' },
      info: { bg: '#dbeafe', border: '#3b82f6', color: '#1e40af' }
    };

    const style = styles[type];

    return (
      <div style={{
        backgroundColor: style.bg,
        borderLeft: `4px solid ${style.border}`,
        padding: '16px',
        marginBottom: '16px'
      }}>
        {title && <strong style={{ color: style.color }}>{title}</strong>}
        <p style={{ color: style.color, margin: title ? '8px 0 0' : 0 }}>
          {children}
        </p>
      </div>
    );
  }

  // Usage
  <Alert type="success" title="Success!">
    Your changes have been saved.
  </Alert>

  <Alert type="error">
    Something went wrong. Please try again.
  </Alert>
  ```
</Accordion>

<Accordion title="Exercise 2: Build a Card System">
  Create a flexible card system with `Card`, `Card.Header`, `Card.Body`, and `Card.Footer`:

  ```javascript theme={null}
  function Card({ children, className = '' }) {
    return (
      <div className={`card ${className}`} style={{
        border: '1px solid #e5e7eb',
        borderRadius: '8px',
        overflow: 'hidden'
      }}>
        {children}
      </div>
    );
  }

  Card.Header = function CardHeader({ children }) {
    return (
      <div style={{ padding: '16px', borderBottom: '1px solid #e5e7eb' }}>
        {children}
      </div>
    );
  };

  Card.Body = function CardBody({ children }) {
    return <div style={{ padding: '16px' }}>{children}</div>;
  };

  Card.Footer = function CardFooter({ children }) {
    return (
      <div style={{ 
        padding: '16px', 
        borderTop: '1px solid #e5e7eb',
        backgroundColor: '#f9fafb'
      }}>
        {children}
      </div>
    );
  };

  // Usage
  <Card>
    <Card.Header>
      <h3>Card Title</h3>
    </Card.Header>
    <Card.Body>
      <p>Card content goes here.</p>
    </Card.Body>
    <Card.Footer>
      <button>Action</button>
    </Card.Footer>
  </Card>
  ```
</Accordion>

<Accordion title="Exercise 3: Avatar Component with Fallback">
  Create an Avatar component that shows initials if no image is provided:

  ```javascript theme={null}
  function Avatar({ src, name, size = 40 }) {
    const getInitials = (name) => {
      return name
        .split(' ')
        .map(word => word[0])
        .join('')
        .toUpperCase()
        .slice(0, 2);
    };

    const colors = ['#ef4444', '#f97316', '#eab308', '#22c55e', '#3b82f6', '#8b5cf6'];
    const colorIndex = name.charCodeAt(0) % colors.length;

    const style = {
      width: size,
      height: size,
      borderRadius: '50%',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      fontSize: size * 0.4,
      fontWeight: 'bold',
      color: 'white',
      backgroundColor: colors[colorIndex]
    };

    if (src) {
      return (
        <img 
          src={src} 
          alt={name} 
          style={{ ...style, objectFit: 'cover' }}
          onError={(e) => e.target.style.display = 'none'}
        />
      );
    }

    return <div style={style}>{getInitials(name)}</div>;
  }

  // Usage
  <Avatar src="/user.jpg" name="John Doe" size={50} />
  <Avatar name="Jane Smith" size={40} />
  ```
</Accordion>

***

## Summary

| Concept                   | Description                                 |
| ------------------------- | ------------------------------------------- |
| **Functional Components** | Functions that return JSX                   |
| **Props**                 | Arguments passed to components (read-only)  |
| **Destructuring**         | Extract props for cleaner code              |
| **Default Props**         | Fallback values when props aren't provided  |
| **children**              | Special prop for nested content             |
| **PropTypes**             | Runtime type checking                       |
| **Composition**           | Building complex UIs from simple components |
| **Spreading Props**       | Pass all props with `{...props}`            |

<Card title="Next Steps" icon="arrow-right">
  In the next chapter, you'll learn about **State & useState** — how to make your components interactive and dynamic!
</Card>

***

## Interview Deep-Dive

<AccordionGroup>
  <Accordion title="What is the difference between the 'children' prop and render props? When would you choose one over the other?">
    **Strong Answer:**
    The `children` prop passes static JSX content between a component's opening and closing tags. The parent decides what to render, and the wrapper component just places it somewhere in its layout. It is the simplest composition pattern -- think of it like a picture frame: the frame does not care what picture you put in it.

    Render props (including function-as-children) are fundamentally different because the parent component passes a *function* that receives data and returns JSX. This means the wrapper component can share its internal state or computed values with the consumer without exposing them through Context or lifting state up. The classic example is a `MouseTracker` that tracks cursor position internally and passes `{ x, y }` to the render function so the consumer can decide how to display it.

    In practice, I reach for `children` when the wrapper is a layout concern (cards, modals, page shells) and does not need to pass data back. I use render props when the wrapper owns logic that the consumer needs access to -- for instance, a `Formik` component that manages form state and passes `{ values, errors, handleChange }` to a render function.

    That said, since hooks arrived, most render prop patterns have been replaced by custom hooks. Instead of a `<MouseTracker>` render prop, you write `useMouse()` and get `{ x, y }` directly. Hooks are more composable and avoid the nesting pyramid that render props create. The only place render props still shine is when you need to conditionally render children based on the wrapper's internal state and the wrapper also controls DOM structure (like a headless dropdown component).

    **Follow-up: The compound components pattern uses React.Children.map and React.cloneElement. What are the downsides of this approach and what is the modern alternative?**

    `React.Children.map` and `cloneElement` are fragile. They only work if the compound children are direct children -- if someone wraps them in a `div` or a fragment, `cloneElement` injects props into the wrong element. They also break TypeScript's type safety because the injected props are invisible to the type system. And they create an implicit API contract: the parent "magically" injects props that the child expects but never declares.

    The modern alternative is to use Context. The parent compound component (like `Accordion`) provides state through a Context, and each child (`AccordionItem`) consumes it with `useContext`. This works regardless of nesting depth, plays well with TypeScript, and makes the data flow explicit. Libraries like Radix UI and Headless UI use this pattern extensively.

    The tradeoff is slightly more boilerplate (creating a Context) and the performance implications of Context re-renders. But for compound components with a handful of children, this is negligible.
  </Accordion>

  <Accordion title="A junior developer on your team puts all component logic in one giant component. How do you explain when and why to split components?">
    **Strong Answer:**
    I would start with concrete signals rather than abstract principles. You should split a component when you see any of these:

    First, the component does two unrelated things. If a component fetches user data AND renders a chart, those are two concerns. The data fetching should live in a container or custom hook, and the chart should be its own presentational component. The test for this: can you describe what the component does in one sentence without using "and"?

    Second, you see duplicated JSX patterns. If three pages each render a card with an avatar, name, and action button, extract a `UserCard` component. The rule of thumb is: if you copy-paste JSX more than once, extract it.

    Third, the component is hard to test. If you need to mock five APIs and set up complex state just to test whether a button turns blue, the component is doing too much. Smaller components have smaller test surfaces.

    Fourth, the file exceeds roughly 200-300 lines. This is not a hard rule, but if you are scrolling a lot, it is a smell.

    What I would not do is split prematurely. A component that renders a form with five fields does not need five separate `FormField` components on day one. Over-splitting creates indirection without benefit -- you end up jumping between 15 files to understand one screen. I follow the "rule of three": the first time you write something, just write it. The second time, note the duplication. The third time, extract it.

    The key mental model is: components are functions, and the same principles apply. A function should do one thing, be testable in isolation, and have a clear interface (props). If your component violates any of these, it is a candidate for splitting.

    **Follow-up: How do you decide whether shared logic should be a component, a custom hook, or a utility function?**

    If the shared logic involves JSX output, it is a component. If it involves React state or lifecycle (hooks), it is a custom hook. If it is pure data transformation with no React dependency, it is a utility function.

    Concrete example: formatting a date is a utility function -- `formatDate(timestamp)`. Tracking window dimensions with a resize listener is a custom hook -- `useWindowSize()`. Rendering a formatted timestamp with a tooltip showing the relative time is a component -- `<Timestamp value={date} />`.

    The mistake I see most often is putting pure logic into hooks unnecessarily. If your "hook" does not call `useState`, `useEffect`, or another hook, it should not be a hook at all -- it should be a plain function. Making it a hook adds the Rules of Hooks constraints for no benefit.
  </Accordion>

  <Accordion title="Explain the concept of props immutability in React. Why can you not modify props, and what would actually happen if you tried?">
    **Strong Answer:**
    Props are read-only because React's rendering model depends on unidirectional data flow: data flows down from parent to child, and the parent is the single source of truth for any prop value. If a child could mutate its props, the parent's state and the child's view of that state would diverge, leading to inconsistencies that are extremely hard to debug.

    If you literally do `props.name = 'changed'` in JavaScript strict mode (which React enforces in development), you get a TypeError because React freezes the props object with `Object.freeze()` in development mode. In production builds, `Object.freeze` is stripped for performance, so the mutation would silently succeed at the JavaScript level -- but React would not know about it and would not re-render. The UI would be stale, or worse, you would corrupt shared object references if the parent passes the same object to multiple children.

    The deeper principle is that React components should be pure functions of their props and state. Given the same props, a component should produce the same output. Mutating props violates this contract and makes components unpredictable, untestable, and impossible to optimize with `React.memo` (which relies on shallow comparison of the previous and next props).

    In practice, if you need to "change" a prop, you have two options: lift the state up to the parent and pass a callback (`onNameChange`), or use local state initialized from the prop (`useState(props.initialName)`). The second approach is common for "initial value" props where the child needs to diverge from the parent's value (like a form input with a default).

    **Follow-up: What is the difference between passing `initialValue` as a prop versus `value` as a prop? How does this affect component design?**

    This is the distinction between controlled and uncontrolled components. When you pass `value`, the parent owns the state and the component must call back via `onChange` to request changes -- the parent is in full control. When you pass `initialValue`, the component copies it into local state on mount and manages it independently from that point.

    The tradeoff: controlled components give the parent full authority over the value (useful for validation, formatting, dependent fields) but require the parent to manage state for every input. Uncontrolled components are simpler for the parent but harder to synchronize if the parent later needs to reset or override the value.

    A common bug with `initialValue` is expecting the component to update when the prop changes after mount. Since `useState(initialValue)` only reads the initial value once, changing the prop later has no effect. If you need to reset, you either need a `key` change to remount the component or a `useEffect` that syncs the prop to state -- which is an anti-pattern the React docs explicitly warn against. The cleanest solution is using `key={userId}` on the component so React unmounts and remounts it with fresh state when the user changes.
  </Accordion>
</AccordionGroup>
