Chapter 3: Components

What is a Component?

A component is a JavaScript function that returns JSX:

function Welcome() {
    return <h1>Hello!</h1>;
}

That's it. A function that returns UI.

Naming Conventions

  • PascalCase for component names: UserCard, LoginForm, NavigationMenu
  • Components starting with lowercase are treated as HTML tags
// CORRECT
function UserCard() { ... }
<UserCard />

// INCORRECT - treated as HTML tag <usercard>
function userCard() { ... }
<userCard />  // Doesn't work!

Props: Passing Data

Props (properties) allow you to pass data to a component:

// Component definition with props
function Welcome({ name }) {
    return <h1>Hello, {name}!</h1>;
}

// Usage
<Welcome name="Jean" />
<Welcome name="Marie" />

Multiple Props

function UserCard({ name, email, role }) {
    return (
        <div className="card">
            <h2>{name}</h2>
            <p>{email}</p>
            <span>{role}</span>
        </div>
    );
}

<UserCard name="Jean" email="jean@example.com" role="Admin" />

Props with Default Values

function Button({ label, type = "button", disabled = false }) {
    return (
        <button type={type} disabled={disabled}>
            {label}
        </button>
    );
}

<Button label="Submit" />
<Button label="Submit" type="submit" />
<Button label="Disabled" disabled={true} />

Different Prop Types

function Product({ name, price, inStock, tags, onClick }) {
    return (
        <div onClick={onClick}>
            <h3>{name}</h3>
            <p>{price} €</p>
            {inStock && <span>In Stock</span>}
            <ul>
                {tags.map(tag => <li key={tag}>{tag}</li>)}
            </ul>
        </div>
    );
}

<Product
    name="Laptop"
    price={999}
    inStock={true}
    tags={['tech', 'sale']}
    onClick={() => console.log('Clicked')}
/>
Type Example
String name="Jean"
Number age={30}
Boolean active={true} or just active
Array items={[1, 2, 3]}
Object user={{ name: 'Jean' }}
Function onClick={() => {}}

Children Prop

The special children prop contains the content between the opening and closing tags:

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

// Usage
<Card title="My Title">
    <p>This is the card content.</p>
    <button>Action</button>
</Card>

This is very useful for creating "wrapper" or "layout" components.

Component Composition

Components can use other components:

function Avatar({ src, alt }) {
    return <img className="avatar" src={src} alt={alt} />;
}

function UserInfo({ name, email }) {
    return (
        <div className="user-info">
            <span className="name">{name}</span>
            <span className="email">{email}</span>
        </div>
    );
}

function UserCard({ user }) {
    return (
        <div className="user-card">
            <Avatar src={user.avatar} alt={user.name} />
            <UserInfo name={user.name} email={user.email} />
        </div>
    );
}

function UserList({ users }) {
    return (
        <div className="user-list">
            {users.map(user => (
                <UserCard key={user.id} user={user} />
            ))}
        </div>
    );
}

Hierarchy: UserList -> UserCard -> Avatar + UserInfo

Props are Read-Only

Fundamental rule: a component should never modify its props.

// INCORRECT - never do this!
function BadComponent({ user }) {
    user.name = "Modified";  // FORBIDDEN!
    return <div>{user.name}</div>;
}

// CORRECT - props are immutable
function GoodComponent({ user }) {
    return <div>{user.name}</div>;
}

If you need to modify data, use state (useState - next module).

Prop Destructuring

Several ways to extract props:

// 1. Destructuring in parameters (recommended)
function UserCard({ name, email }) {
    return <div>{name} - {email}</div>;
}

// 2. Destructuring in body
function UserCard(props) {
    const { name, email } = props;
    return <div>{name} - {email}</div>;
}

// 3. Without destructuring
function UserCard(props) {
    return <div>{props.name} - {props.email}</div>;
}

Prop Spread

To forward all props to a child element:

function Button({ children, ...rest }) {
    return (
        <button className="btn" {...rest}>
            {children}
        </button>
    );
}

// Usage - onClick and disabled are passed to button
<Button onClick={handleClick} disabled={isLoading}>
    Submit
</Button>

File Organization

SmartMaker convention: one component per folder with index.jsx:

src/components/
├── UserCard/
│   └── index.jsx
├── UserList/
│   └── index.jsx
└── common/
    ├── Button/
    │   └── index.jsx
    └── Card/
        └── index.jsx
// src/components/UserCard/index.jsx
export default function UserCard({ user }) {
    return (
        <div className="user-card">
            <h3>{user.name}</h3>
            <p>{user.email}</p>
        </div>
    );
}

// Import
import UserCard from 'src/components/UserCard';

Exercises

Exercise 1: Create a Button Component

Create a Button component that accepts:

  • label: button text
  • variant: "primary" or "secondary" (default: "primary")
  • onClick: function to call on click

Solution:

function Button({ label, variant = "primary", onClick }) {
    return (
        <button
            className={`btn btn-${variant}`}
            onClick={onClick}
        >
            {label}
        </button>
    );
}

// Usage
<Button label="Submit" onClick={() => console.log('Submitted')} />
<Button label="Cancel" variant="secondary" onClick={handleCancel} />

Exercise 2: Composition

Create a component structure to display a list of products:

  • ProductList: receives an array of products
  • ProductCard: displays a product (name, price)
  • Price: displays a formatted price with € symbol

Solution:

function Price({ value }) {
    return <span className="price">{value.toFixed(2)} €</span>;
}

function ProductCard({ product }) {
    return (
        <div className="product-card">
            <h3>{product.name}</h3>
            <Price value={product.price} />
        </div>
    );
}

function ProductList({ products }) {
    return (
        <div className="product-list">
            {products.map(product => (
                <ProductCard key={product.id} product={product} />
            ))}
        </div>
    );
}

// Usage
const products = [
    { id: 1, name: 'Laptop', price: 999.99 },
    { id: 2, name: 'Phone', price: 699.50 }
];

<ProductList products={products} />

Key Points to Remember

  1. Component = function that returns JSX
  2. PascalCase for component names
  3. Props: data passed to the component (read-only)
  4. children: content between the tags
  5. Composition: components that use other components
  6. Destructuring: function Component({ prop1, prop2 })

Module 2 Summary

You now know the basics of React:

Concept Description
JSX Syntax for writing UI in JavaScript
Component Function that returns JSX
Props Data passed to a component
children Content between tags
key Unique identifier for lists
Fragment <></> to return multiple elements

<- Previous Chapter | Back to Module | Next Module: Fundamentals Hooks ->