---
title: "Chapitre 3 : Composants"
weight: 380
---

# Chapitre 3 : Composants

## Qu'est-ce qu'un composant ?

Un composant est une fonction JavaScript qui retourne du JSX :

```javascript
function Welcome() {
    return <h1>Bonjour !</h1>;
}
```

C'est tout. Une fonction qui retourne de l'UI.

## Conventions de nommage

- **PascalCase** pour les noms de composants : `UserCard`, `LoginForm`, `NavigationMenu`
- Les composants commençant par une minuscule sont traités comme des balises HTML

```javascript
// CORRECT
function UserCard() { ... }
<UserCard />

// INCORRECT - traité comme une balise HTML <usercard>
function userCard() { ... }
<userCard />  // Ne fonctionne pas !
```

## Props : passer des données

Les props (properties) permettent de passer des données à un composant :

```javascript
// Définition du composant avec props
function Welcome({ name }) {
    return <h1>Bonjour, {name} !</h1>;
}

// Utilisation
<Welcome name="Jean" />
<Welcome name="Marie" />
```

### Plusieurs props

```javascript
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 avec valeur par défaut

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

<Button label="Envoyer" />
<Button label="Soumettre" type="submit" />
<Button label="Désactivé" disabled={true} />
```

### Props de type différent

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

<Product
    name="Laptop"
    price={999}
    inStock={true}
    tags={['tech', 'promo']}
    onClick={() => console.log('Cliqué')}
/>
```

| Type | Exemple |
| --- | --- |
| String | `name="Jean"` |
| Number | `age={30}` |
| Boolean | `active={true}` ou juste `active` |
| Array | `items={[1, 2, 3]}` |
| Object | `user={{ name: 'Jean' }}` |
| Function | `onClick={() => {}}` |

## Props children

La prop spéciale `children` contient le contenu entre les balises ouvrante et fermante :

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

// Utilisation
<Card title="Mon titre">
    <p>Ceci est le contenu de la carte.</p>
    <button>Action</button>
</Card>
```

C'est très utile pour créer des composants "wrapper" ou "layout".

## Composition de composants

Les composants peuvent utiliser d'autres composants :

```javascript
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>
    );
}
```

Hiérarchie : `UserList` -> `UserCard` -> `Avatar` + `UserInfo`

## Props sont en lecture seule

**Règle fondamentale** : un composant ne doit jamais modifier ses props.

```javascript
// INCORRECT - ne jamais faire ça !
function BadComponent({ user }) {
    user.name = "Modifié";  // INTERDIT !
    return <div>{user.name}</div>;
}

// CORRECT - les props sont immuables
function GoodComponent({ user }) {
    return <div>{user.name}</div>;
}
```

Si vous devez modifier des données, utilisez l'état (useState - prochain module).

## Déstructuration des props

Plusieurs façons de récupérer les props :

```javascript
// 1. Déstructuration dans les paramètres (recommandé)
function UserCard({ name, email }) {
    return <div>{name} - {email}</div>;
}

// 2. Déstructuration dans le corps
function UserCard(props) {
    const { name, email } = props;
    return <div>{name} - {email}</div>;
}

// 3. Sans déstructuration
function UserCard(props) {
    return <div>{props.name} - {props.email}</div>;
}
```

## Spread de props

Pour transférer toutes les props à un élément enfant :

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

// Utilisation - onClick et disabled sont passés au button
<Button onClick={handleClick} disabled={isLoading}>
    Envoyer
</Button>
```

## Organisation des fichiers

Convention SmartMaker : un composant par dossier avec `index.jsx` :

```
src/components/
├── UserCard/
│   └── index.jsx
├── UserList/
│   └── index.jsx
└── common/
    ├── Button/
    │   └── index.jsx
    └── Card/
        └── index.jsx
```

```javascript
// 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';
```

## Exercices

### Exercice 1 : Créer un composant Button

Créer un composant `Button` qui accepte :

- `label` : texte du bouton
- `variant` : "primary" ou "secondary" (défaut: "primary")
- `onClick` : fonction à appeler au clic

**Solution :**

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

// Utilisation
<Button label="Envoyer" onClick={() => console.log('Envoyé')} />
<Button label="Annuler" variant="secondary" onClick={handleCancel} />
```

### Exercice 2 : Composition

Créer une structure de composants pour afficher une liste de produits :

- `ProductList` : reçoit un tableau de produits
- `ProductCard` : affiche un produit (nom, prix)
- `Price` : affiche un prix formaté avec le symbole €

**Solution :**

```javascript
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>
    );
}

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

<ProductList products={products} />
```

## Points clés à retenir

1. **Composant** = fonction qui retourne du JSX
2. **PascalCase** pour les noms de composants
3. **Props** : données passées au composant (lecture seule)
4. **children** : contenu entre les balises
5. **Composition** : composants qui utilisent d'autres composants
6. **Déstructuration** : `function Component({ prop1, prop2 })`

## Récapitulatif du Module 2

Vous connaissez maintenant les bases de React :

| Concept | Description |
| --- | --- |
| JSX | Syntaxe pour écrire de l'UI en JavaScript |
| Composant | Fonction qui retourne du JSX |
| Props | Données passées à un composant |
| children | Contenu entre les balises |
| key | Identifiant unique pour les listes |
| Fragment | `<></>` pour retourner plusieurs éléments |

[← Chapitre précédent](/training/module2-introduction-react/jsx) | [Retour au module](/training/module2-introduction-react) | [Module suivant : Hooks Fondamentaux ->](/training/module3-hooks-fondamentaux)
