Composants de cache dans Next.js : pages plus rapides avec pré-rendu partiel
Les performances de rendu dans les applications Web sont souvent limitées par le travail du serveur qui ne peut pas être effectué instantanément. La récupération des données, la personnalisation et l’agrégation backend prennent du temps. Dans de nombreuses applications, ce travail bloque la page entière, laissant les utilisateurs avec un écran vide jusqu’à ce que tout soit terminé.
Next.js gère traditionnellement cela via un modèle statique par défaut. Un itinéraire est soit statique, soit dynamique, et cette décision s’applique à la page entière. Cela fonctionne bien pour les cas simples, mais cela devient restrictif à mesure que les applications se développent. La plupart des pages réelles combinent des données prévisibles avec des données spécifiques à la requête, mais elles sont forcées d’adopter un seul mode de rendu.
Next.js 16 introduit des composants de cache pour résoudre cette limitation. Les composants de cache fonctionnent au niveau des composants et s’appuient sur le pré-rendu partiel. Le pré-rendu partiel permet à un shell de page de s’afficher immédiatement tandis que les sections plus lentes sont différées. Les composants de cache étendent ce modèle en vous donnant le contrôle sur les parties de la page qui peuvent être réutilisées sans bloquer le reste.
Dans cet article, nous examinons comment les composants de cache s’intègrent dans le pipeline de rendu Next.js et comment ils modifient la façon dont le contenu statique et dynamique coexiste sur la même page.
🚀 Inscrivez-vous à la newsletter The Replay
La rediffusion est une newsletter hebdomadaire destinée aux responsables du développement et de l’ingénierie.
Livré une fois par semaine, il s’agit de votre guide organisé sur les conversations les plus importantes autour du développement frontend, des outils d’IA émergents et de l’état des logiciels modernes.
Un aperçu rapide du pré-rendu partiel (PPR)
Les pages modernes traitent rarement un seul type de données. La navigation et la mise en page sont souvent prévisibles, les données de catalogue ou de contenu changent occasionnellement et les données de personnalisation ou de session doivent être calculées à chaque demande. Lorsque tout ce travail est traité en une seule passe de rendu, l’opération la plus lente détermine quand quelque chose peut être affiché.
Le pré-rendu partiel évite cela en permettant à la page de s’afficher par étapes. Un shell statique est envoyé en premier pour établir la structure, tandis que les sections dynamiques sont enveloppées dans des limites Suspense et rendues indépendamment :

Une fois le rendu de ces sections terminé, elles sont diffusées vers le client sans bloquer le reste de la page. Les utilisateurs voient les progrès au lieu d’un écran vide.
Le pré-rendu partiel améliore la façon dont les pages sont livrées, mais il ne décide pas de la fréquence à laquelle le travail du serveur doit s’exécuter ni si son résultat peut être réutilisé. Cette limitation est ce qui rend les composants de cache nécessaires.
Présentation des composants de cache
Même si le pré-rendu partiel améliore la façon dont les pages sont livrées, il ne change pas ce qui se passe sur le serveur. Les sections dynamiques s’exécutent toujours lorsqu’une requête arrive. Si une section récupère les mêmes données à chaque requête, ce travail est répété même lorsque le résultat est identique.
C’est la lacune que les composants de cache sont censés combler. Avec les composants de cache, les décisions de mise en cache se déplacent au niveau des composants. Au lieu de traiter un itinéraire entier comme statique ou dynamique, vous marquez des parties spécifiques de l’interface utilisateur comme pouvant être mises en cache et laissez le reste dynamique. Cela permet de réutiliser une sortie prévisible rendue par le serveur sans affecter les sections spécifiques à la requête :

Le diagramme montre la même page affichée sur deux requêtes distinctes :
Demande 1 représente la première fois que la page est rendue. Toutes les sections s’exécutent sur le serveur. Composants marqués C sont éligibles à la mise en cache, leur sortie est donc calculée et stockée. Composants marqués D sont dynamiques et exécutés dans le cadre de la demande.
Demande 2 représente une demande ultérieure pour la même page. Les composants mis en cache ne s’exécutent plus. Leur sortie précédemment rendue est réutilisée. Les composants dynamiques s’exécutent toujours sur le serveur car ils dépendent de données spécifiques à la requête.
La mise en page de la page ne change pas entre les demandes. Ce qui change, c’est le cycle de vie de chaque section. Les composants de cache permettent de réutiliser des parties prévisibles de la page entre les requêtes, tandis que les parties dynamiques continuent de s’exécuter à chaque fois.
Configuration des composants du cache
Pour démontrer pleinement les composants du cache, il est utile de voir d’abord comment une page se comporte sans eux. Pour cette raison, j’ai créé une application qui utilise la méthode traditionnelle. Vous pouvez trouver le référentiel GitHub pour cela ici.
Cette version n’utilise aucun composant de cache sous aucune forme. Tout se passe dans un seul rendu de serveur. Vous pouvez le confirmer dans le next.config.ts:
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
Sur la page elle-même, le rendu dynamique est explicitement forcé. Cela garantit que chaque requête exécute une nouvelle logique de serveur et que rien n’est réutilisé.
import ProductGrid from '@/components/product-grid'; // 2 seconds import Recommendations from '@/components/recommendations'; // 3 seconds import Orders from '@/components/orders'; // 2 seconds
Vous remarquerez qu’il existe trois sources de données indépendantes :
- Produits, qui prennent environ deux secondes
- Recommandations, qui prennent environ trois secondes
- Commandes récentes, qui prennent environ deux secondes
Étant donné que ces appels sont attendus les uns après les autres, le temps d’attente total du serveur est d’environ sept secondes. Plus important encore, l’instruction return ne s’exécute qu’une fois la requête finale terminée. Jusque-là, React n’a rien à restituer. Pour le confirmer, démarrez l’application en exécutant la commande :
npm run dev
Accédez à La première chose que vous remarquez est l’absence de quoi que ce soit. Il n’y a pas d’en-tête. Aucune mise en page. Aucun état de chargement. Le navigateur est vide :
Lorsque la page finit par s’afficher, elle le fait au bout de sept secondes environ. Ce délai existe parce que la page est structurée pour attendre la donnée la plus lente avant de restituer quoi que ce soit. En pratique, la plupart des interfaces utilisateur n’ont pas besoin d’attendre. L’en-tête, le pied de page et toute autre partie de la page qui ne dépend pas de données lentes peuvent s’afficher immédiatement.
C’est là qu’intervient le pré-rendu partiel. Le pré-rendu partiel permet à une page de restituer d’abord un shell statique, tandis que les sections plus lentes sont différées. Il vous permet de mélanger les types de rendu sur la même page. Cependant, cela présente une limite. Bien que les sections différées puissent être diffusées, elles sont toujours recalculées à chaque demande. Le pré-rendu partiel améliore la livraison, mais il ne permet pas la mise en cache de ces sections dynamiques. Cette limitation est ce qui nous amène aux composants de cache.
Configurons maintenant les composants du cache.
Tout d’abord, nous devrons configurer les composants de cache afin de les activer, car ils sont encore en phase expérimentale. Ouvrir next.config.ts et mettez-le à jour comme suit :
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
useCache: true,
},
};
export default nextConfig;
Ce drapeau permet au use cache et indique à Next.js d’autoriser la mise en cache au niveau des composants.
Ensuite, nous avons besoin d’un endroit pour définir la durée de vie des données mises en cache. Dans l’application, chaque requête récupère tout. Nous voulons changer cela avec les composants de cache afin de pouvoir avoir un contrôle explicite sur la fraîcheur.
Autres articles intéressants de LogRocket :
Créez un nouveau fichier àlib/cache-config.ts:
export const cacheProfiles = {
products: {
stale: 3600, // 1 hour
revalidate: 7200, // 2 hours
expire: 86400, // 24 hours
},
};
Il est important de noter que ce fichier ne modifie pas le comportement par lui-même. Il centralise simplement la politique de cache afin qu’elle puisse être réutilisée entre les composants.
Rendre la grille de produits pouvant être mise en cache
Ouvrir components/product-grid.tsx et remplacez son contenu par la version mise en cache ci-dessous :
'use cache';
import { fetchProducts } from '@/lib/demo-data';
import { cacheProfiles } from '@/lib/cache-config';
export async function cacheLife() {
return cacheProfiles.products;
}
export default async function ProductGrid() {
const products = await fetchProducts();
return (
<section style={{ marginBottom: '3rem' }}>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1.5rem' }}>
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold' }}>Products</h2>
</div>
<div className="grid grid-4">
{products.map(product => (
<div key={product.id} className="card fade-in">
<div style={{ fontSize: '3rem', marginBottom: '0.5rem' }}>{product.image}</div>
<h3 style={{ fontSize: '1.125rem', fontWeight: '600', marginBottom: '0.25rem' }}>
{product.name}
</h3>
<p style={{ color: '#888', fontSize: '0.875rem', marginBottom: '0.5rem' }}>
{product.category}
</p>
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<span style={{ fontSize: '1.25rem', fontWeight: 'bold', color: '#10b981' }}>
${product.price}
</span>
<span style={{ fontSize: '0.875rem', color: '#888' }}>
Stock: {product.stock}
</span>
</div>
</div>
))}
</div>
</section>
);
}
En haut du fichier se trouve le 'use cache'signal, qui indique à Next.js que ce composant peut être réutilisé au lieu d’être recalculé à chaque requête. Sans cela, le composant se comporte exactement comme avant et s’exécute à chaque rendu de la page.
Nous avons également ajouté la fonction cacheLife(), qui nous permet de décider combien de temps la grille de produits doit rester. Étant donné que les produits ne changent pas à chaque demande, il est logique de les réutiliser pendant un certain temps plutôt que de les récupérer constamment. Au lieu de mettre en cache la page entière, cette approche nous permet d’être délibéré et de mettre en cache uniquement la section qui en bénéficie.
Isolez les sections lentes avec Suspense
Après avoir mis en cache la grille de produits, l’objectif suivant est de laisser la page s’afficher dès que possible, tandis que seules les sections qui dépendent de données lentes sont autorisées à attendre. C’est là que Suspense entre en jeu. Il nous permet de marquer les parties de la page qui peuvent se charger plus tard. Ainsi, pendant que ces sections sont encore en cours de résolution sur le serveur, React peut envoyer le reste de la page au navigateur et combler les lacunes par la suite.
Pour rendre ce retard visible, nous avons besoin de quelque chose à afficher à la place du contenu réel.
Créez un nouveau fichier à components/loading-skeleton.tsx:
export default function LoadingSkeleton({ count = 4 }: { count?: number }) {
return (
<div className="grid grid-4">
{Array.from({ length: count }).map((_, i) => (
<div key={i} className="card skeleton" />
))}
</div>
);
}
Le code ci-dessus génère une petite grille de cartes qui correspondent à peu près à la forme des vignettes du produit dans l’interface utilisateur, de sorte que la page ne semble pas vide pendant que nous attendons l’arrivée des données réelles.
Maintenant ouvert app/page.tsxet remplacez son contenu par ce qui suit :
import './globals.css';
import { Suspense } from 'react';
import { getTimestamp } from '@/lib/demo-data';
import LoadingSkeleton from '@/components/loading-skeleton';
import ProductGrid from '@/components/product-grid';
import Recommendations from '@/components/recommendations';
import Orders from '@/components/orders';
export const dynamic="force-dynamic";
export default function CacheApp() {
const timestamp = getTimestamp();
return (
<>
<div className="container" style={{ padding: '2rem 1rem' }}>
{/* Header Banner */}
<div style={{
marginBottom: '2rem',
padding: '1.5rem',
background: '#065f46',
borderRadius: '12px',
border: '2px solid #10b981'
}}>
<h1 style={{ fontSize: '2rem', fontWeight: 'bold', marginBottom: '0.5rem' }}>
Ecommerce App
</h1>
<p style={{ fontSize: '1rem', color: '#86efac', marginBottom: '0.5rem' }}>
Cached content renders immediately, while dynamic sections load progressively.
</p>
<p style={{ fontSize: '0.875rem', color: '#d1fae5', fontFamily: 'monospace' }}>
Rendered at: {timestamp}
</p>
</div>
<Suspense fallback={
<section style={{ marginBottom: '3rem' }}>
<div style={{ marginBottom: '1.5rem' }}>
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold' }}>Products</h2>
<p style={{ color: '#888', fontSize: '0.875rem' }}>Loading products...</p>
</div>
<LoadingSkeleton count={4} />
</section>
}>
<ProductGrid />
</Suspense>
<Suspense fallback={
<section style={{ marginBottom: '3rem' }}>
<div style={{ marginBottom: '1.5rem' }}>
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold' }}>Recommended for You</h2>
<p style={{ color: '#888', fontSize: '0.875rem' }}>Loading personalized recommendations...</p>
</div>
<LoadingSkeleton count={3} />
</section>
}>
<Recommendations userId="user-123" />
</Suspense>
<Suspense fallback={
<section style={{ marginBottom: '3rem' }}>
<div style={{ marginBottom: '1.5rem' }}>
<h2 style={{ fontSize: '1.5rem', fontWeight: 'bold' }}>Recent Orders</h2>
<p style={{ color: '#888', fontSize: '0.875rem' }}>Loading your orders...</p>
</div>
<LoadingSkeleton count={3} />
</section>
}>
<Orders userId="user-123" />
</Suspense>
<div style={{
padding: '2rem',
background: '#1a1a1a',
borderRadius: '12px',
border: '1px solid #2a2a2a',
textAlign: 'center'
}}>
<h3 style={{ fontSize: '1.25rem', marginBottom: '1rem', color: '#10b981' }}>
Improved User Experience
</h3>
<p style={{ color: '#888', maxWidth: '600px', margin: '0 auto' }}>
The page renders immediately with cached content, while user-specific sections
load progressively without blocking the rest of the UI.
</p>
</div>
</div>
</>
);
}
Désormais, la page n’est plus obligée d’attendre chaque source de données avant le rendu. L’en-tête apparaît immédiatement et chaque section basée sur les données peut se charger à son propre rythme. La grille de produits est enveloppée dans Suspense afin que la page puisse s’afficher même lors d’un chargement à froid, tandis que sa sortie mise en cache est résolue instantanément lors des demandes ultérieures. Les sections de recommandations et de commandes s’exécutent toujours par requête, mais elles ne bloquent plus le reste de l’interface utilisateur. Au lieu de cela, les espaces réservés apparaissent en premier et sont remplacés dès que les données sont prêtes.
Redémarrez l’application et accédez à Cette fois, l’en-tête et la grille de produits apparaissent immédiatement, et le minuteur confirme que le premier contenu s’affiche presque instantanément. Les recommandations et les commandes ne bloquent plus la page. Leurs squelettes apparaissent en premier, et le contenu réel arrive au fur et à mesure qu’il est prêt :
Comparaison des performances
Les utilisateurs ne connaissent pas les architectures. Ils subissent du temps de chargement. Le tableau ci-dessous résume le comportement des deux versions lors du chargement de la page :
| Métrique | Application traditionnelle | Composants du cache |
|---|---|---|
| Délai de mise en ligne du premier contenu | ~7 secondes | < 100 ms |
| Expérience initiale | Écran vide | Interface utilisateur immédiate |
| Blocage total du serveur | ~7 secondes | Près de zéro |
| Catalogue de produits | Rendu des blocs (~ 2 s) | En cache, instantané au rechargement |
| Recommandations | Page des blocs (~ 3 s) | Flux dans |
| Ordres | Page des blocs (~ 2 s) | Flux dans |
| Modèle de rendu | Tout ou rien | Progressif |
| Temps de chargement perçu | Lent | Rapide |
Meilleures pratiques lors de l’utilisation des composants de cache
Les composants de cache sont puissants, mais ils fonctionnent mieux lorsqu’ils sont appliqués délibérément. Vous trouverez ci-dessous quelques-unes des meilleures pratiques lorsque vous travaillez avec des composants de cache :
- Ne mélangez pas les API d’exécution avec les composants mis en cache
- Gardez les limites de Suspense claires et hiérarchiques
- Mettre en cache les sections déterministes uniquement (par exemple, liste de produits, navigation)
- Surveillez la taille et la durée de vie du cache pour éviter les données obsolètes ou les actualisations lentes
- Préférez les balises aux vidages manuels pour des mises à jour contrôlées
Conclusion
Les composants de cache modifient la façon dont les décisions de rendu sont prises dans Next.js. Au lieu de choisir entre statique et dynamique au niveau de la page, vous pouvez décider au niveau du composant quelles parties de l’interface utilisateur doivent être réutilisées et lesquelles doivent rester spécifiques à la demande.
Dans l’exemple que nous avons parcouru, l’amélioration n’est pas venue de la réécriture de l’application ou de la modification du modèle de données. Cela est venu de la séparation du travail prévisible du travail spécifique à l’utilisateur et de la possibilité pour chacun d’être rendu selon sa propre chronologie. Les composants mis en cache réduisaient le travail répété du serveur, tandis que Suspense garantissait que les sections plus lentes ne bloquaient plus le reste de la page.
Pour plus de détails sur les composants de cache, le pré-rendu partiel et les API associées, consultez la documentation officielle Next.js.
Berita Terkini
Berita Terbaru
Daftar Terbaru
News
Berita Terbaru
Flash News
RuangJP
Pemilu
Berita Terkini
Prediksi Bola
Togel Deposit Pulsa
Technology
Otomotif
Berita Terbaru
Daftar Judi Slot Online Terpercaya
Slot yang lagi gacor
Teknologi
Berita terkini
Berita Pemilu
Berita Teknologi
Hiburan
master Slote
Berita Terkini
Pendidikan
Resep
Jasa Backlink
One Piece Terbaru

