Kodeloka
  1. Kodeloka
  2. Kelas Next.js
  3. Materi

Data & Caching · Modul 12 dari 23

Cache Components & Direktif 'use cache'

Model caching eksplisit Next.js modern: menandai fungsi atau komponen sebagai dapat di-cache dengan 'use cache', mengatur masa berlakunya, dan membatalkannya lewat tag.

🎯 Poin-Poin Utama Modul Ini:
  • Sejak Next.js 15, fetch TIDAK lagi di-cache secara bawaan — kebalikan dari Next 13/14
  • 'use cache' menandai fungsi, komponen, atau seluruh berkas sebagai dapat di-cache
  • cacheLife mengatur masa berlaku, cacheTag menandai untuk pembatalan tertarget
  • Argumen fungsi dan nilai baliknya harus dapat diserialisasi

📌 Kenapa Model Caching Berubah

Next.js 13 dan 14 melakukan caching secara agresif dan implisit: fetch() otomatis di-cache selamanya kecuali Anda menolaknya. Niatnya baik, hasilnya membingungkan — orang men-deploy aplikasi lalu bertanya-tanya kenapa datanya tidak pernah berubah.

⚠️ Perubahan bawaan yang wajib diketahui

Sejak Next.js 15, defaultnya dibalik menjadi tidak di-cache:

// Next 13/14: di-cache selamanya secara diam-diam
// Next 15/16: TIDAK di-cache, selalu ambil baru
const res = await fetch('https://api.contoh.com/produk');

// Route Handler GET juga tidak lagi di-cache secara bawaan.
// Begitu pula navigasi client-side router cache.

Kalau Anda mengikuti tutorial era Next 13/14, asumsi caching di dalamnya sudah tidak berlaku. Caching sekarang harus diminta secara eksplisit.

💻 Direktif 'use cache'

Ditempatkan di baris pertama fungsi, komponen, atau berkas — menandai bahwa hasilnya boleh disimpan dan dipakai ulang.

app/produk/data.ts
import { unstable_cacheLife as cacheLife,
         unstable_cacheTag as cacheTag } from 'next/cache'

export async function ambilProduk(kategori: string) {
  'use cache'

  cacheLife('hours')            // profil masa berlaku
  cacheTag(`produk-${kategori}`) // tag untuk pembatalan tertarget

  const res = await fetch(`https://api.contoh.com/produk/${kategori}`)
  return res.json()
}

Tiga tingkat penerapan:

// 1. Seluruh berkas — semua ekspor di dalamnya dapat di-cache
'use cache'
export async function a() { ... }
export async function b() { ... }

// 2. Satu komponen
async function DaftarProduk({ kategori }) {
  'use cache'
  const produk = await ambilProduk(kategori)
  return <ul>{produk.map(p => <li key={p.id}>{p.nama}</li>)}</ul>
}

// 3. Satu fungsi saja (contoh paling atas)

⏱️ Mengatur Masa Berlaku dengan cacheLife

cacheLife('seconds')   // sangat sering berubah
cacheLife('minutes')
cacheLife('hours')
cacheLife('days')
cacheLife('max')       // praktis permanen sampai dibatalkan

// Profil kustom di next.config.ts
export default {
  experimental: {
    cacheLife: {
      katalog: {
        stale: 60,        // detik — klien boleh pakai versi lama
        revalidate: 300,  // detik — server menyegarkan di latar
        expire: 3600,     // detik — setelah ini WAJIB ambil baru
      },
    },
  },
}

// lalu: cacheLife('katalog')
💡 Bedanya stale, revalidate, dan expire
  • stale — berapa lama peramban boleh memakai salinannya tanpa bertanya ke server.
  • revalidate — kapan server mulai menyegarkan di latar belakang, sementara pengunjung tetap dilayani versi lama. Inilah stale-while-revalidate.
  • expire — batas keras. Setelah ini, permintaan harus menunggu data baru.

🏷️ Pembatalan dengan Tag

app/aksi.ts
'use server'
import { revalidateTag, revalidatePath } from 'next/cache'

export async function simpanProduk(data: FormData) {
  await db.produk.create({ ... })

  // Hanya membuang cache yang bertag ini
  revalidateTag('produk-elektronik')

  // Atau berdasarkan path
  revalidatePath('/produk')
}
⚠️ Argumen dan nilai balik harus dapat diserialisasi

Fungsi ber-'use cache' menyimpan hasilnya di luar proses, sehingga argumen dipakai sebagai bagian kunci cache dan nilai baliknya harus bisa diserialisasi. Melewatkan fungsi, kelas, atau objek Date yang tidak standar akan bermasalah. Lewatkan nilai primitif dan objek biasa saja.

🚫 Jangan menaruh data per-pengguna di dalam 'use cache'

Cache dibagi antar seluruh pengunjung. Bila fungsi ber-'use cache' membaca cookie atau header untuk menentukan hasil, pengguna A bisa menerima data milik pengguna B. Data yang bergantung pada identitas harus berada di luar lapisan cache — atau jadikan ID pengguna sebagai argumen eksplisit sehingga ikut menjadi bagian kunci cache.

🧭 Status Kestabilan

Kemampuan ini diperkenalkan bertahap dan sebagian API-nya masih memakai awalan unstable_ tergantung versi persis yang Anda pakai. Sebelum menerapkannya di produksi, jalankan npx next info untuk memastikan versi Anda, dan periksa apakah cacheComponents (atau dynamicIO pada versi yang lebih awal) perlu diaktifkan di next.config.ts. Konsep dan model mentalnya stabil; nama flag-nya yang masih bergerak.