Kinerja rendering dalam aplikasi web seringkali dibatasi oleh pekerjaan server yang tidak dapat diselesaikan secara instan. Pengambilan data, personalisasi, dan agregasi backend semuanya membutuhkan waktu. Di banyak aplikasi, pekerjaan ini memblokir seluruh halaman, meninggalkan pengguna dengan layar kosong hingga semuanya selesai.
Next.js secara tradisional menangani ini melalui model statis secara default. Rute bersifat statis atau dinamis, dan keputusan tersebut berlaku untuk seluruh halaman. Ini bekerja dengan baik untuk kasus-kasus sederhana, namun menjadi terbatas seiring berkembangnya aplikasi. Sebagian besar halaman nyata menggabungkan data yang dapat diprediksi dengan data khusus permintaan, namun halaman tersebut dipaksa ke dalam mode rendering tunggal.
Next.js 16 memperkenalkan Komponen Cache untuk mengatasi batasan ini. Komponen Cache beroperasi pada tingkat komponen dan dibangun di atas Pra-Rendering Parsial. Pra-Rendering Parsial memungkinkan shell halaman untuk segera dirender sementara bagian yang lebih lambat ditunda. Komponen Cache memperluas model ini dengan memberi Anda kendali atas bagian halaman mana yang dapat digunakan kembali tanpa memblokir bagian lainnya.
Dalam artikel ini, kita melihat bagaimana Komponen Cache masuk ke dalam pipeline rendering Next.js dan bagaimana komponen tersebut mengubah cara konten statis dan dinamis hidup berdampingan di halaman yang sama.
🚀 Mendaftar untuk buletin The Replay
Pemutaran Ulang adalah buletin mingguan untuk para pemimpin pengembang dan teknik.
Disampaikan seminggu sekali, ini adalah panduan pilihan Anda untuk percakapan paling penting seputar pengembangan frontend, alat AI yang sedang berkembang, dan keadaan perangkat lunak modern.
Sekilas tentang Pra-Rendering Parsial (PPR)
Halaman modern jarang hanya menangani satu jenis data. Navigasi dan tata letak sering kali dapat diprediksi, data katalog atau konten terkadang berubah, dan data personalisasi atau sesi harus dihitung pada setiap permintaan. Ketika semua pekerjaan ini ditangani dalam satu render pass, operasi paling lambat menentukan kapan sesuatu dapat ditampilkan.
Pra-Rendering Parsial menghindari hal ini dengan mengizinkan halaman dirender secara bertahap. Shell statis dikirim terlebih dahulu untuk membentuk struktur, sementara bagian dinamis dibungkus dalam batas Suspense dan dirender secara independen:

Saat bagian tersebut selesai dirender, bagian tersebut dialirkan ke klien tanpa memblokir halaman lainnya. Pengguna melihat kemajuan, bukan layar kosong.
Pra-Rendering Parsial meningkatkan cara pengiriman halaman, namun tidak menentukan seberapa sering pekerjaan server harus dijalankan atau apakah hasilnya dapat digunakan kembali. Keterbatasan itulah yang membuat Komponen Cache diperlukan.
Memperkenalkan komponen cache
Meskipun Pra-Rendering Parsial meningkatkan cara pengiriman halaman, hal ini tidak mengubah apa yang terjadi di server. Bagian dinamis tetap berjalan ketika ada permintaan masuk. Jika suatu bagian mengambil data yang sama pada setiap permintaan, pekerjaan itu diulangi bahkan ketika hasilnya sama.
Inilah celah yang ingin diatasi oleh Komponen Cache. Dengan Komponen Cache, keputusan caching dipindahkan ke tingkat komponen. Daripada memperlakukan seluruh rute sebagai statis atau dinamis, Anda menandai bagian tertentu dari UI sebagai dapat di-cache dan membiarkan sisanya dinamis. Hal ini memungkinkan untuk menggunakan kembali keluaran yang dirender oleh server yang dapat diprediksi tanpa memengaruhi bagian khusus permintaan:

Diagram menunjukkan halaman yang sama sedang dirender pada dua permintaan terpisah:
Permintaan 1 mewakili pertama kali halaman dirender. Semua bagian dijalankan di server. Komponen ditandai C memenuhi syarat untuk cache, sehingga outputnya dihitung dan disimpan. Komponen ditandai D bersifat dinamis dan dijalankan sebagai bagian dari permintaan.
Permintaan 2 mewakili permintaan selanjutnya untuk halaman yang sama. Komponen yang di-cache tidak dapat dijalankan lagi. Output yang diberikan sebelumnya digunakan kembali. Komponen dinamis masih berjalan di server karena bergantung pada data khusus permintaan.
Tata letak halaman tidak berubah antar permintaan. Yang berubah adalah siklus hidup setiap bagian. Komponen Cache memungkinkan bagian halaman yang dapat diprediksi untuk digunakan kembali di seluruh permintaan, sementara bagian dinamis terus berjalan setiap saat.
Mengonfigurasi komponen cache
Untuk mendemonstrasikan Komponen Cache sepenuhnya, ada baiknya jika Anda terlebih dahulu melihat bagaimana perilaku halaman tanpa komponen tersebut. Untuk alasan ini, saya membangun sebuah aplikasi yang menggunakan cara tradisional. Anda dapat menemukan repositori GitHub untuk ini di sini.
Versi ini tidak menggunakan Komponen Cache dalam bentuk apapun. Semuanya terjadi dalam satu server render. Anda dapat mengonfirmasinya di next.config.ts:
// next.config.ts
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
};
export default nextConfig;
Pada halaman itu sendiri, rendering dinamis secara eksplisit dipaksakan. Hal ini memastikan bahwa setiap permintaan menjalankan logika server baru dan tidak ada yang digunakan kembali.
import ProductGrid from '@/components/product-grid'; // 2 seconds import Recommendations from '@/components/recommendations'; // 3 seconds import Orders from '@/components/orders'; // 2 seconds
Anda akan melihat bahwa ada tiga sumber data independen:
- Produk, yang memakan waktu sekitar dua detik
- Rekomendasi, yang memakan waktu sekitar tiga detik
- Pesanan terbaru, yang memakan waktu sekitar dua detik
Karena panggilan-panggilan ini ditunggu satu demi satu, total waktu tunggu server kira-kira tujuh detik. Lebih penting lagi, pernyataan return hanya berjalan setelah permintaan terakhir selesai. Sampai saat itu tiba, React tidak punya apa pun untuk dirender. Untuk mengonfirmasi hal ini, mulai aplikasi dengan menjalankan perintah:
npm run dev
Navigasikan ke Hal pertama yang Anda perhatikan adalah tidak adanya apa pun. Tidak ada tajuk. Tidak ada tata letak. Tidak ada status pemuatan. Peramban kosong:
Saat halaman akhirnya dirender, halaman tersebut akan dirender dalam waktu sekitar tujuh detik. Penundaan tersebut terjadi karena halaman disusun untuk menunggu bagian data paling lambat sebelum merender apa pun. Dalam praktiknya, sebagian besar UI tidak perlu menunggu. Header, footer, dan bagian halaman lainnya yang tidak bergantung pada data lambat dapat segera dirender.
Di sinilah peran Pra-Rendering Parsial. Pra-Rendering Parsial memungkinkan halaman untuk merender shell statis terlebih dahulu, sementara bagian yang lebih lambat ditunda. Ini memungkinkan Anda mencampur jenis rendering pada halaman yang sama. Namun, ia mempunyai keterbatasan. Meskipun bagian yang ditangguhkan dapat dialirkan, bagian tersebut masih dihitung ulang pada setiap permintaan. Pra-Rendering Parsial meningkatkan pengiriman, namun tidak memungkinkan bagian dinamis tersebut di-cache. Keterbatasan itulah yang membawa kita ke Komponen Cache.
Sekarang mari kita konfigurasikan komponen cache.
Pertama, kita perlu mengonfigurasi komponen cache untuk mengaktifkannya, karena komponen tersebut masih dalam tahap percobaan. Membuka next.config.ts dan perbarui sebagai berikut:
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
useCache: true,
},
};
export default nextConfig;
Bendera ini memungkinkan use cache direktif dan memberitahu Next.js untuk mengizinkan caching di tingkat komponen.
Selanjutnya, kita memerlukan tempat untuk menentukan berapa lama data cache akan bertahan. Di aplikasi, setiap permintaan mengambil ulang semuanya. Kami ingin mengubahnya dengan Komponen Cache sehingga kami dapat memiliki kontrol eksplisit atas kesegaran.
Lebih banyak artikel bagus dari LogRocket:
Buat file baru dilib/cache-config.ts:
export const cacheProfiles = {
products: {
stale: 3600, // 1 hour
revalidate: 7200, // 2 hours
expire: 86400, // 24 hours
},
};
Penting untuk diperhatikan bahwa file ini tidak mengubah perilaku dengan sendirinya. Itu hanya memusatkan kebijakan cache sehingga dapat digunakan kembali di seluruh komponen.
Jadikan grid produk dapat di-cache
Membuka components/product-grid.tsx dan ganti isinya dengan versi cache di bawah ini:
'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>
);
}
Di bagian atas file adalah 'use cache'sinyal, yang memberi tahu Next.js bahwa komponen ini diizinkan untuk digunakan kembali alih-alih dihitung ulang pada setiap permintaan. Tanpanya, komponen akan berperilaku persis seperti sebelumnya dan berjalan setiap kali halaman dirender.
Kami juga menambahkan fungsi cacheLife(), yang mana kami memutuskan berapa lama grid produk harus bertahan. Karena produk tidak berubah pada setiap permintaan, masuk akal untuk menggunakannya kembali untuk jangka waktu tertentu daripada mengambilnya terus-menerus. Alih-alih menyimpan seluruh halaman dalam cache, pendekatan ini memungkinkan kita untuk berhati-hati dan hanya menyimpan cache pada bagian yang mendapat manfaat darinya.
Isolasi bagian yang lambat dengan Suspense
Setelah menyimpan grid produk dalam cache, tujuan selanjutnya adalah membiarkan halaman dirender sesegera mungkin, sementara hanya bagian yang bergantung pada data lambat yang diperbolehkan menunggu. Di situlah Suspense berperan. Ini memungkinkan kita menandai bagian halaman yang dapat dimuat nanti, jadi sementara bagian tersebut masih diselesaikan di server, React dapat mengirimkan sisa halaman ke browser dan mengisi kekosongan setelahnya.
Untuk membuat penundaan itu terlihat, kita memerlukan sesuatu untuk ditampilkan sebagai pengganti konten sebenarnya.
Buat file baru di 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>
);
}
Kode di atas menampilkan kotak kecil kartu yang kira-kira sesuai dengan bentuk ubin produk di UI, sehingga halaman tidak terasa kosong saat kita menunggu data sebenarnya tiba.
Sekarang buka app/page.tsxdan ganti isinya dengan yang berikut ini:
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>
</>
);
}
Kini, halaman tidak lagi dipaksa menunggu setiap sumber data sebelum dirender. Header segera muncul, dan setiap bagian berdasarkan data diizinkan memuat dengan kecepatannya sendiri. Kisi produk dibungkus dengan Suspense sehingga halaman dapat dirender bahkan pada pemuatan dingin, sementara keluaran cache-nya diselesaikan secara instan pada permintaan berikutnya. Bagian rekomendasi dan pesanan masih berjalan per permintaan, namun tidak lagi memblokir UI lainnya. Sebaliknya, placeholder muncul terlebih dahulu dan diganti segera setelah data siap.
Mulai ulang aplikasi dan navigasikan ke Kali ini, header dan kisi produk segera muncul, dan pengatur waktu mengonfirmasi bahwa konten pertama ditampilkan hampir seketika. Rekomendasi dan pesanan tidak lagi memblokir halaman. Kerangka mereka muncul terlebih dahulu, dan konten sebenarnya mengalir masuk saat sudah siap:
Perbandingan kinerja
Pengguna tidak merasakan arsitektur. Mereka mengalami waktu buka. Tabel di bawah ini merangkum perilaku kedua versi selama pemuatan halaman:
| Metrik | Aplikasi tradisional | Komponen cache |
|---|---|---|
| Saatnya Konten Pertama | ~7 detik | < 100 ms |
| Pengalaman Awal | Layar kosong | UI langsung |
| Pemblokiran Server Total | ~7 detik | Mendekati nol |
| Katalog Produk | Blok dirender (~2 detik) | Di-cache, instan saat dimuat ulang |
| Rekomendasi | Blokir halaman (~3 detik) | Streaming masuk |
| Pesanan | Blokir halaman (~2 detik) | Streaming masuk |
| Model Rendering | Semua atau tidak sama sekali | Progresif |
| Waktu Muat yang Dirasakan | Lambat | Cepat |
Praktik terbaik saat menggunakan komponen cache
Komponen Cache sangat kuat, namun berfungsi paling baik bila diterapkan dengan sengaja. Berikut adalah beberapa praktik terbaik saat bekerja dengan komponen cache:
- Jangan gabungkan API runtime dengan komponen yang di-cache
- Jaga agar batasan Ketegangan tetap jelas dan hierarkis
- Hanya bagian deterministik cache (misalnya, daftar produk, navigasi)
- Pantau ukuran dan masa pakai cache untuk menghindari data basi atau penyegaran yang lambat
- Lebih memilih tag daripada pembilasan manual untuk pembaruan terkontrol
Kesimpulan
Komponen Cache mengubah cara pengambilan keputusan rendering di Next.js. Daripada memilih antara statis dan dinamis di tingkat halaman, Anda dapat memutuskan di tingkat komponen bagian UI mana yang harus digunakan kembali dan bagian mana yang harus tetap spesifik permintaan.
Dalam contoh yang kami lalui, peningkatan tidak datang dari penulisan ulang aplikasi atau perubahan model data. Ini berasal dari pemisahan pekerjaan yang dapat diprediksi dari pekerjaan khusus pengguna dan memungkinkan masing-masing pekerjaan dirender pada timeline-nya sendiri. Komponen yang disimpan dalam cache mengurangi pekerjaan server yang berulang, sementara Suspense memastikan bahwa bagian yang lebih lambat tidak lagi memblokir sisa halaman.
Untuk detail selengkapnya tentang komponen cache, pra-render sebagian, dan API terkait, lihat dokumentasi resmi 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

