Performance et bonnes pratiques

Optimisations et patterns à éviter

Optimisations

Optimisations de performance

React.memo — éviter les re-renders inutiles

// L'enfant se re-rend seulement si ses props changent
const ListItem = React.memo(function ListItem({ item, onDelete }) {
  return (
    <li>
      {item.nom}
      <button onClick={() => onDelete(item.id)}>Supprimer</button>
    </li>
  );
});

Code splitting — lazy loading

import { lazy, Suspense } from 'react';

// Chargé seulement quand la route est visitée
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));

function App() {
  return (
    <Suspense fallback={<Spinner />}>
      <Routes>
        <Route path="/dashboard" element={<Dashboard />} />
        <Route path="/settings" element={<Settings />} />
      </Routes>
    </Suspense>
  );
}

Virtualisation des listes

Pour des listes de centaines/milliers d'éléments, n'afficher que ce qui est visible :

npm install @tanstack/react-virtual

import { useVirtualizer } from '@tanstack/react-virtual';

function GrandeListe({ items }) {
  const parentRef = useRef(null);

  const virtualizer = useVirtualizer({
    count: items.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 50,
  });

  return (
    <div ref={parentRef} style={{ height: '400px', overflow: 'auto' }}>
      <div style={{ height: virtualizer.getTotalSize() }}>
        {virtualizer.getVirtualItems().map(vItem => (
          <div key={vItem.index} style={{ transform: `translateY(${vItem.start}px)` }}>
            {items[vItem.index].nom}
          </div>
        ))}
      </div>
    </div>
  );
}

Bonnes pratiques

Bonnes pratiques React

Structure de fichiers

src/
├── components/          # Composants réutilisables
│   ├── Button/
│   │   ├── Button.jsx
│   │   └── Button.css
│   └── Modal/
├── pages/               # Composants de page (1 par route)
├── hooks/               # Custom hooks
├── contexts/            # Contextes React
├── services/            # Appels API
├── utils/               # Fonctions utilitaires
└── types/               # TypeScript types/interfaces

Règles à respecter

Anti-patterns courants

// ❌ Synchroniser deux états (état dérivé)
const [items, setItems] = useState([]);
const [count, setCount] = useState(0);
// Chaque ajout doit mettre à jour les deux

// ✅ Calculer le dérivé
const [items, setItems] = useState([]);
const count = items.length; // Calculé, pas stocké

// ❌ useEffect pour synchroniser des states
useEffect(() => setFullName(first + " " + last), [first, last]);

// ✅ Variable calculée
const fullName = first + " " + last;

// ❌ Key = index (problèmes lors de réordonnancement)
{items.map((item, i) => <Item key={i} />)}

// ✅ Key = ID stable
{items.map(item => <Item key={item.id} />)}