Pré-rendu partiel et rendu concurrent expliqués
Découvrez comment le pré-rendering partiel de Next.js et le rendu concurrentiel de React résolvent tous deux le problème des applications lentes en permettant aux frameworks d’organiser et de diffuser les tâches, plutôt que de traiter les rendus comme une seule unité bloquante.
Les efforts visant à améliorer les performances de React et Next.js reviennent constamment au même principe : c’est en forçant toute une page ou tout un rendu à fonctionner comme une seule unité ininterrompue que les applications semblent lentes. Deux techniques abordent ce problème sous des angles différents — le pré-rendu partiel, qui permet à une seule route Next.js de combiner du contenu statique et dynamique, et le rendu concurrentiel, qui permet à React d’interrompre et de réorganiser les tâches au sein du navigateur. Ensemble, elles illustrent un schéma important à comprendre : les améliorations de performance proviennent de plus en plus non pas de l’écriture de code « plus rapide », mais du fait que le framework peut planifier et exécuter les tâches de manière plus intelligente.
Le vieux choix du rendu tout ou rien
Pendant longtemps, une page Next.js ne disposait que de deux modes de rendu possibles :
- Génération statique (SSG) — les pages s’affichent rapidement car elles sont préparées à l’avance, mais leur contenu devient obsolète jusqu’à la prochaine reconstruction.
- Rendu du côté serveur (SSR) — le contenu est toujours à jour, mais chaque demande doit attendre la transmission des données les plus lentes avant que quoi que ce soit ne soit renvoyé.
Le problème est que la plupart des pages réelles ne correspondent pas parfaitement à l’un ou l’autre de ces modèles. Une page de produit, par exemple, est principalement statique : le layout, la navigation et les textes de marketing ne changent pas à chaque demande — mais elle contient également quelques éléments véritablement dynamiques, tels qu’un badge de panier ou un compteur de stock en temps réel. Rendre toute la page via SSR uniquement pour maintenir à jour un petit widget signifie payer le coût complet du rendu serveur pour du contenu qui n’en avait pas besoin.
Permettre à une route d’être à la fois statique et dynamique
Le pré-rendering partiel (PPR) a été conçu pour combler cette lacune. Il permet à une seule route de livrer immédiatement un noyau statique, tandis que les fragments dynamiques qu’elle contient sont chargés dès que leurs données sont disponibles — sans pages séparées, et sans avoir à alterner entre getStaticProps et getServerSideProps.
// app/product/[id]/page.tsx
import { Suspense } from 'react';
import ProductShell from '@/components/ProductShell';
import LiveInventory from '@/components/LiveInventory';
export default function ProductPage({ params }: { params: { id: string } }) {
return (
<ProductShell productId={params.id}>
{/* static instantly, no waiting on the network */}
<Suspense fallback={<InventorySkeleton />}>
{/* streamed in once the dynamic data resolves */}
<LiveInventory productId={params.id} />
</Suspense>
</ProductShell>
);
}
Le mécanisme repose sur une frontière Suspense. Tout ce qui se trouve en dehors est pré-renderisé au moment de la compilation et servi instantanément ; tout ce qui est placé à l’intérieur est calculé et chargé au moment de la demande. Telle est l’idée fondamentale : un seul fichier, une seule route, deux stratégies de rendu coexistant.
Cette approche permet plusieurs avantages concrets. Le temps nécessaire pour afficher le premier octet diminue, car la coque statique est fournie directement depuis le serveur distant au lieu d’être calculée pour chaque requête. Il n’est pas non plus nécessaire d’avoir un état de chargement complet de la page : les visiteurs voient immédiatement les parties statiques et pertinentes, tandis que les éléments dynamiques plus petits s’affichent progressivement une fois leur traitement terminé. De plus, la charge mentale est moindre par rapport à la gestion de pages statiques et de pages générées côté serveur séparément, puisqu’on travaille avec une seule route et un seul fichier qui combine simplement différentes stratégies. L’équipe de Next.js décrit cet objectif comme celui d’offrir les avantages tant du rendu statique que du rendu dynamique, sans les compromis architecturaux habituels.
Quelques directives pratiques permettent d’assurer l’efficacité du PPR en production. Restez strict sur les limites de Suspense uniquement pour les parties véritablement dynamiques — en incluant trop de contenu, on annule complètement l’intérêt du pré-rendering. Gardez les squelettes de secours légers, car ces derniers font eux-mêmes partie du noyau rendu statiquement. Si vous utilisez TypeScript, définissez des contrats de propriétés clairs entre le noyau statique et les composants chargés dynamiquement afin que ces deux éléments restent synchronisés au fil de leur évolution. Et lors des tests, réduisez la vitesse de votre connexion à quelque chose comme un 3G lent dans les outils de développement du navigateur — les avantages du PPR deviennent beaucoup plus évidents dans des conditions réseau réalistes qu’avec une connexion locale rapide.
Si votre équipe utilise Next.js 14 ou une version ultérieure, il est judicieux d’essayer le PPR sur une seule route avant de l’adopter dans toute l’application. Il ne s’agit pas d’un terme marketing ; c’est une stratégie de rendu qui correspond enfin au comportement réel des pages — partiellement statiques, partiellement dynamiques, en même temps.
Extension de cette même idée au rendu côté client
Le pré-rendering partiel résout le problème de la séparation entre contenu statique et dynamique au niveau du serveur et du réseau. Le rendu concurrent, introduit avec React 18 et affiné dans React 19, résout un problème similaire à l’intérieur du navigateur : au lieu de choisir entre « rendre tout de suite » et « ne rien rendre pour l’instant », React peut désormais rendre certaines éléments immédiatement tout en laissant d’autres attendre.
Au préalable à React 18, le rendu était synchrone et bloquant. Une seule mise à jour d’état déclenchait un nouveau rendu qui s’exécutait jusqu’au bout, quelles que soient les conséquences — même si cela signifiait geler le défilement ou les saisies pendant que React traitait toute la structure.
Le rendu concurrent change ce comportement. React peut désormais interrompre partiellement un rendu, donner la priorité aux mises à jour urgentes comme la saisie ou le clic par rapport à celles qui ne le sont pas, telles que le filtrage d’une longue liste, et abandonner les tâches en cours si une mise à jour plus récente les rend inutiles. Il est important de noter qu’il ne s’agit pas d’une nouvelle API à apprendre depuis zéro — c’est un modèle de planification différent qui fonctionne en arrière-plan derrière les hooks que vous utilisez déjà.
Les hooks qui exposent la planification concurrente
useTransition vous permet de marquer une mise à jour d’état comme non urgente, afin que React puisse maintenir l’interface réactive pendant que cette mise à jour est traitée en arrière-plan.
function ProductSearch() {
const [query, setQuery] = useState("");
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();
function handleChange(e) {
const value = e.target.value;
setQuery(value); // urgent — keep input snappy
startTransition(() => {
// non-urgent — can be interrupted
setResults(filterProducts(value));
});
}
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <span className="text-gray-400">Updating…</span>}
<ResultsList items={results} />
</>
);
}
Avec ce modèle, la saisie dans une zone de recherche reste fluide même lorsque des milliers d’éléments sont filtrés en arrière-plan.
Suspense joue un rôle similaire de streaming du côté client, tout comme dans PPR du côté serveur : au lieu de bloquer toute la page pendant le chargement des données, il permet aux différentes parties de l’interface d’être traitées indépendamment. Associé au Next.js App Router, cela permet également aux composants serveur de s’afficher progressivement dans la page sans retarder le chargement global.
useDeferredValue traite un cas apparenté mais distinct : des re-render coûteux causés par des valeurs provenant de props ou du contexte, et non de l’état local du composant. Il permet à React de différer le rec calcul de ces parties coûteuses jusqu’à ce qu’il dispose de temps libre.
Pour les équipes travaillant avec React, Next.js, TypeScript, Redux et Tailwind CSS, ce modèle de planification est important au-delà des hooks individuels — les nouveaux schémas asynchrones de Redux Toolkit ainsi que le fonctionnement des Server Actions de Next.js reposent tous deux sur la même planification concurrente sous-jacente fournie désormais par React. La concurrence n’est pas quelque chose que l’on active directement ; c’est une capacité que React met en œuvre automatiquement dès que vos composants sont structurés de manière à permettre l’interruption et la reprise de leur rendu.
À retenir
Quelle que soit la technique utilisée, le principe fondamental reste le même : traiter une page entière ou un rendu complet comme une unité indivisible est ce qui provoque des lenteurs, et non nécessairement un code inefficace. Le rendu concurrentiel ne vise pas à écrire du code plus rapide, mais plutôt à planifier de manière plus intelligente le code que l’on possède déjà. En pratique, cela signifie différer les mises à jour d’état non urgentes à l’aide de useTransition, afficher les données par flux avec Suspense, et tester sur des appareils moins puissants, car c’est là que les avantages de la concurrence sont les plus visibles. Associé au pré-rendu partiel du côté serveur, ces outils permettent à une seule route ou à un seul arbre de composants de fournir du contenu statique instantanément, tandis que le contenu dynamique n’est chargé qu’au moment opportun — le meilleur des deux mondes du rendu, sans avoir à restructurer toute l’architecture autour d’un extrême ou de l’autre.
Lectures complémentaires
- À l’intérieur de la réécriture en Go de TypeScript 7 : des gains de vitesse sans modifications de code — Découvrez comment le compilateur basé sur Go de TypeScript 7 permet des builds 8 à 12 fois plus rapides, pourquoi ce changement d’architecture fonctionne, et comment mettre à niveau en toute sécurité des projets existants.
- Les primitifs SSR de React 19.2 : Activity, cacheSignal et PPR expliqués — Apprenez comment le nouveau composant Activity, cacheSignal et le pré-rendering partiel de React 19.2 donnent aux développeurs un contrôle direct sur les performances du rendu serveur.