Bonjour !
Dans la leçon précédente, nous avons exploré une technique d'optimisation fondamentale, l'instanciation, pour afficher des milliers d'objets sans détruire les performances. Nous nous sommes concentrés sur l'optimisation de ce qui se passe pendant que l'application tourne. Aujourd'hui, nous allons nous attaquer à un autre moment tout aussi critique pour l'expérience utilisateur : le temps de chargement initial.
Les modèles 3D, les textures haute résolution et les environnements peuvent être des fichiers très lourds. Laisser un utilisateur face à un écran blanc ou figé pendant que ces ressources se téléchargent est le meilleur moyen de le faire fuir.
L'objectif de cette leçon est donc de vous apprendre à gérer l'expérience de chargement avec Suspense et le hook useProgress. Nous allons transformer cette attente inévitable en une partie intégrante et professionnelle de votre application.
1. Le Problème : L'Absence d'État de Chargement
En tant que développeur web, vous avez l'habitude d'afficher des "spinners" ou des indicateurs de chargement lors des appels API. Le principe est exactement le même en 3D, mais l'enjeu est souvent plus grand en raison de la taille des fichiers. Ne pas gérer ce temps d'attente est considéré comme un anti-pattern majeur.
3d-web-experience | Skills Marketplace - LobeHub
Ce document met en évidence plusieurs anti-patterns dans le développement 3D. L'un d'eux nous concerne directement aujourd'hui.
Trouvez la section "Anti-Patterns" et lisez le point "❌ No Loading State". Il explique de manière concise pourquoi le fait de ne pas avoir d'indicateur de chargement est si préjudiciable à l'expérience utilisateur.
Comme vous l'avez lu, un utilisateur qui ne voit rien se passer pensera que votre site est cassé. La solution est de lui donner un retour visuel clair que le contenu est en cours de préparation.
2. La Solution Déclarative : React Suspense
React nous offre un outil puissant et élégant pour gérer les opérations asynchrones comme le chargement de données ou de composants : le composant Suspense.
L'idée de Suspense est simple : il vous permet d' "envelopper" un ou plusieurs composants qui pourraient avoir besoin de temps pour se charger. Pendant ce temps d'attente, Suspense affichera une interface de secours (un "fallback").
Dans l'écosystème React Three Fiber, les hooks que nous utilisons pour charger des ressources, comme useGLTF (pour les modèles 3D) ou useTexture (pour les textures), sont conçus pour fonctionner avec Suspense. Lorsqu'un composant utilise l'un de ces hooks, il "suspend" son rendu jusqu'à ce que la ressource soit entièrement chargée. Suspense intercepte cette suspension et affiche le fallback à la place.
La structure de base ressemble à ceci :
import { Suspense } from 'react';
import { Canvas } from '@react-three/fiber';
import { Model } from './Model'; // Un composant qui utilise useGLTF
function App() {
return (
<Canvas>
<Suspense fallback={<mesh /> /* Un simple mesh vide en attendant */}>
<Model />
<Environment /> {/* Un autre composant qui pourrait suspendre */}
</Suspense>
</Canvas>
);
}
Le fallback peut être n'importe quel composant React. Ça peut être un composant 3D simple, du JSX vide (null), ou même du HTML, comme nous allons le voir.
3. Créer un Indicateur de Chargement Personnalisé
Afficher un simple cube ou un écran noir, c'est bien, mais afficher un véritable indicateur de progression, c'est beaucoup mieux. Pour cela, nous allons combiner deux outils :
- Le composant
<Html>de@react-three/dreipour afficher du HTML standard à l'intérieur de notre scène 3D. - Le hook
useProgressde@react-three/dreipour obtenir le pourcentage de chargement en temps réel.
Le hook useProgress se connecte au gestionnaire de chargement par défaut de Three.js (DefaultLoadingManager). Tous les chargeurs (GLTFLoader, TextureLoader, etc.) y rapportent leur progression, et useProgress nous la retransmet de manière réactive.
Voyons comment assembler cela.
3d-web-experience | Skills Marketplace - LobeHub
Le document que nous avons consulté précédemment contient un exemple de code parfait qui combine Suspense, <Html>, et useProgress pour créer un chargeur simple et efficace.
Trouvez la section "Loading in R3F" au début du document. Analysez attentivement l'exemple de code. Vous y verrez un composant Loader qui utilise useProgress pour récupérer la progression et <Html> pour l'afficher, et comment il est ensuite utilisé comme fallback pour Suspense.
Recréons cet exemple pour bien le comprendre :
1. Créez un composant Loader :
import { Html, useProgress } from '@react-three/drei';
function Loader() {
// useProgress nous retourne un objet, nous extrayons la propriété 'progress'.
const { progress } = useProgress();
return (
<Html center>
{/* Affiche le pourcentage de chargement, arrondi à l'entier */}
<p style={{ color: 'white' }}>{progress.toFixed(0)} % loaded</p>
</Html>
);
}
2. Utilisez-le dans Suspense :
import { Suspense } from 'react';
import { Canvas } from '@react-three/fiber';
import { Model } from './Model';
import Loader from './Loader';
function App() {
return (
<Canvas>
{/* Le fallback est maintenant notre composant Loader personnalisé */}
<Suspense fallback={<Loader />}>
{/* Tous les composants ici qui chargent des assets
provoqueront l'affichage du Loader. */}
<Model />
</Suspense>
</Canvas>
);
}
Avec ce simple ajout, votre application passe d'une expérience "cassée" à une expérience professionnelle et transparente pour l'utilisateur.
4. Le Hook useProgress et le composant <Loader> de drei
Le hook useProgress est très puissant et retourne plus d'informations que juste progress. Il retourne un objet complet : const { active, progress, errors, item, loaded, total } = useProgress(). Cela vous permet de créer des écrans de chargement très détaillés, affichant par exemple le nom du fichier en cours de chargement (item) ou le nombre de fichiers chargés (loaded/total).
Cependant, pour beaucoup de cas d'usage, un simple indicateur de chargement suffit. La librairie drei nous fournit pour cela un composant tout-en-un : <Loader />.
C'est un composant qui affiche une barre de progression et un pourcentage par-dessus votre Canvas, avec un style par défaut très propre. Il utilise useProgress en interne.
Documentation de `drei` sur GitHub
La documentation de la librairie drei sur GitHub explique comment utiliser à la fois le hook useProgress et le composant <Loader>.
Lisez les deux premières sections : "Loader" et "useProgress". Portez une attention particulière à la syntaxe d'utilisation du composant <Loader />. Notez comment il est placé en dehors du <Canvas> et comment le fallback de Suspense est mis à null.
L'utilisation du composant <Loader> est encore plus simple :
import { Suspense } from 'react';
import { Canvas } from '@react-three/fiber';
import { Loader } from '@react-three/drei';
import { Model } from './Model';
function App() {
return (
<>
<Canvas>
{/* On veut toujours que Suspense intercepte le chargement,
mais on ne veut pas qu'il affiche de fallback.
Le composant Loader s'en charge. */}
<Suspense fallback={null}>
<Model />
</Suspense>
</Canvas>
{/* Le composant Loader gère tout l'affichage de la progression. */}
<Loader />
</>
);
}
Quand choisir useProgress vs <Loader /> ?
- Utilisez
<Loader />pour une solution rapide, facile et efficace qui couvre 90% des besoins. Vous pouvez même personnaliser ses styles. - Utilisez
useProgresslorsque vous avez besoin d'un contrôle total sur l'apparence et le comportement de votre écran de chargement, par exemple pour créer une animation 3D personnalisée qui réagit à la progression.

Conclusion
Vous savez désormais comment offrir une expérience utilisateur fluide et professionnelle même lorsque votre application 3D charge des ressources volumineuses. C'est une compétence essentielle qui distingue un projet amateur d'une application de qualité production.
Points clés à retenir :
- Ne jamais laisser un utilisateur face à un écran vide pendant le chargement ; c'est un anti-pattern majeur.
- React
<Suspense>est le mécanisme déclaratif pour gérer les états d'attente lors du chargement de composants ou de données. - Le
fallbackdeSuspenseest le composant qui sera affiché pendant le chargement. - Le hook
useProgressdedreivous donne un accès réactif à la progression du chargement (progress,loaded,total, etc.) pour construire des indicateurs personnalisés. - Le composant
<Loader />dedreiest une solution prête à l'emploi, simple et efficace, pour afficher un écran de chargement complet.
Aperçu de la prochaine leçon :
Nous savons maintenant comment gérer l'attente. La prochaine étape logique est de réduire cette attente. Dans la leçon suivante, nous allons aborder une autre technique d'optimisation cruciale : la compression de géométrie avec Draco. Vous découvrirez comment réduire de manière drastique la taille de vos modèles 3D, et donc leur temps de chargement, sans sacrifier la qualité visuelle.