0 XP
?
Intermédiaire55 min35 XP

Objectifs de cette leçon

  • Développer une interface avec l'assistance IA
  • Générer des composants UI efficacement
  • Styler et responsive avec l'IA

Développer une application web 🌐

La stack moderne

┌─────────────────────────────────┐
│          Next.js                │
│   (React + SSR + Routing)       │
├─────────────────────────────────┤
│        Tailwind CSS             │
│   (Styling utility-first)       │
├─────────────────────────────────┤
│        TypeScript               │
│   (Typage statique)             │
├─────────────────────────────────┤
│          API REST               │
│   (Communication backend)       │
└─────────────────────────────────┘

Structure d'un projet Next.js

mon-app/
├── src/
│   ├── app/               # Routes (App Router)
│   │   ├── layout.tsx     # Layout global
│   │   ├── page.tsx       # Page d'accueil
│   │   ├── courses/
│   │   │   ├── page.tsx   # /courses
│   │   │   └── [id]/
│   │   │       └── page.tsx   # /courses/1
│   │   └── api/           # Routes API
│   ├── components/        # Composants réutilisables
│   │   ├── ui/            # Composants de base
│   │   └── features/      # Composants métier
│   ├── lib/               # Utilitaires
│   ├── hooks/             # Hooks personnalisés
│   └── types/             # Types TypeScript
├── public/                # Assets statiques
├── package.json
└── tailwind.config.ts

Les composants

Composant de base

// components/ui/Button.tsx
interface ButtonProps {
  children: React.ReactNode;
  variant?: "primary" | "secondary" | "danger";
  size?: "sm" | "md" | "lg";
  onClick?: () => void;
}

export function Button({ children, variant = "primary", size = "md", onClick }: ButtonProps) {
  return (
    <button
      onClick={onClick}
      className={cn(
        "rounded-lg font-medium transition-colors",
        variant === "primary" && "bg-indigo-600 text-white hover:bg-indigo-500",
        variant === "secondary" && "bg-zinc-700 text-zinc-200 hover:bg-zinc-600",
        variant === "danger" && "bg-red-600 text-white hover:bg-red-500",
        size === "sm" && "px-3 py-1.5 text-sm",
        size === "md" && "px-4 py-2 text-base",
        size === "lg" && "px-6 py-3 text-lg",
      )}
    >
      {children}
    </button>
  );
}

Composant de liste

// components/features/UserList.tsx
"use client";

import { useState, useEffect } from "react";

interface User {
  id: number;
  name: string;
  email: string;
}

export function UserList() {
  const [users, setUsers] = useState<User[]>([]);
  const [loading, setLoading] = useState(true);

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

  if (loading) return <div>Chargement...</div>;

  return (
    <div className="space-y-2">
      {users.map((user) => (
        <div key={user.id} className="p-3 rounded-lg bg-zinc-800 border border-zinc-700">
          <p className="text-sm font-medium text-zinc-200">{user.name}</p>
          <p className="text-xs text-zinc-400">{user.email}</p>
        </div>
      ))}
    </div>
  );
}

La gestion d'état

useState (état local)

const [count, setCount] = useState(0);
const [user, setUser] = useState<User | null>(null);

Context (état partagé)

const AuthContext = createContext<AuthContextType | null>(null);

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

Zustand (état global)

import { create } from 'zustand';

interface StoreState {
  count: number;
  increment: () => void;
}

const useStore = create<StoreState>((set) => ({
  count: 0,
  increment: () => set((state) => ({ count: state.count + 1 })),
}));

Les appels API

// Avec fetch
const response = await fetch("/api/users");
const data = await response.json();

// Avec gestion d'erreur
try {
  const response = await fetch("/api/users", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name, email }),
  });

  if (!response.ok) throw new Error("Erreur");

  const data = await response.json();
} catch (error) {
  console.error("Erreur:", error);
}

Utiliser l'IA pour le frontend

Bon prompt :

Crée un composant React UserCard qui affiche :
- Avatar (initiales du nom)
- Nom complet
- Email
- Badge de rôle (admin/user)

Props : user: { name, email, role }
Style : Tailwind CSS, thème sombre, responsive

Exercices 🎯

  1. Composant : Créez un composant Card réutilisable avec props enfants.
  2. Page : Créez une page /dashboard avec un tableau de données.
  3. API : Connectez votre frontend à l'API backend créée au module précédent.
  4. Responsive : Assurez que votre application fonctionne sur mobile.

Prochaine leçon : Développer une application mobile.

Workflow développement web
Interactif
Composants React

Découper l'UI en composants réutilisables.

Étape 1/6