Table des matières

Chapitre 3 : Composants

Qu'est-ce qu'un composant ?

Un composant est une fonction JavaScript qui retourne du JSX :

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

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

Conventions de nommage

snippet.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 :

snippet.javascript
// Définition du composant avec props
function Welcome({ name }) {
    return <h1>Bonjour, {name} !</h1>;
}
 
// Utilisation
<Welcome name="Jean" />
<Welcome name="Marie" />

Plusieurs props

snippet.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

snippet.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

snippet.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 :

snippet.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 :

snippet.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 : UserListUserCardAvatar + UserInfo

Props sont en lecture seule

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

snippet.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 :

snippet.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 :

snippet.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
snippet.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 :

Solution :

snippet.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 :

Solution :

snippet.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 | Retour au module | Module suivant : Hooks Fondamentaux →