nextjslayouttemplateMenengah3 mnt baca

Template vs Layout

Perbedaan template.tsx dan layout.tsx: kapan state harus reset.

Satu file beda, perilaku beda jauh

layout.tsx dan template.tsx terlihat kembar: keduanya menerima children dan membungkus halaman. Bedanya muncul pada satu pertanyaan: apa yang terjadi saat pengguna navigasi antar halaman dalam segmen yang sama?

layout.tsxtemplate.tsx
Di-render ulang saat navigasi?TidakYa
State di dalamnya bertahan?YaTidak, mount ulang dari nol
Effect jalan ulang?TidakYa
Cocok untukUI persistenReset tiap navigasi

Analoginya: layout itu seperti bingkai foto yang menempel di dinding, fotonya diganti tapi bingkainya tetap. Template itu seperti bingkai yang ikut diganti baru setiap kali fotonya diganti.

Contoh 1: membuktikan bedanya dengan counter

Cara tercepat memahami bedanya adalah eksperimen langsung dengan counter:

tsx
// app/layout-demo/layout.tsx
"use client";

import { useState } from "react";

export default function DemoLayout({ children }: { children: React.ReactNode }) {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Counter layout: {count}</p>
      <button onClick={() => setCount(count + 1)}>Tambah</button>
      {children}
    </div>
  );
}
tsx
// app/template-demo/template.tsx
"use client";

import { useState } from "react";

export default function DemoTemplate({ children }: { children: React.ReactNode }) {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>Counter template: {count}</p>
      <button onClick={() => setCount(count + 1)}>Tambah</button>
      {children}
    </div>
  );
}

Buat dua halaman di masing-masing folder, naikkan counter sampai 5, lalu navigasi antar halaman dalam folder yang sama. Di versi layout, angka 5 bertahan karena komponen tidak di-mount ulang. Di versi template, angka kembali ke 0 karena seluruh subtree di-mount ulang total setiap navigasi.

Contoh 2: kapan template memang dibutuhkan

Template dipakai saat reset state tiap navigasi adalah perilaku yang diinginkan, bukan bug:

tsx
// app/survey/template.tsx
export default function SurveyTemplate({ children }: { children: React.ReactNode }) {
  return <div className="animate-fade-in">{children}</div>;
}

Kasus yang cocok untuk template:

  • Form multi-langkah: jawaban step 1 tidak boleh terbawa saat pengguna mundur lalu maju lagi dengan data baru.
  • Animasi enter-page: animasi fade-in harus diputar ulang setiap halaman dibuka, bukan sekali saja di awal.
  • Survey atau kuis: state jawaban harus bersih total setiap pindah soal, tidak boleh ada sisa jawaban soal sebelumnya.

Perhatikan contoh di atas: template juga bisa dipakai murni sebagai pembungkus animasi tanpa state sama sekali. Setiap navigasi, div di-mount ulang sehingga animasi CSS animate-fade-in terpicu kembali.

Satu hal yang sering ditanyakan: template dan layout bisa dipakai bersamaan dalam satu folder. Urutannya selalu layout di luar, template di dalam, lalu page. Jadi kamu bisa punya sidebar persisten dari layout sekaligus animasi yang selalu terpicu ulang dari template.

Aturan praktis: default selalu layout.tsx. Pakai template.tsx hanya kalau kamu bisa menjawab dengan jelas "kenapa state harus reset saat navigasi di section ini". Kalau ragu, layout jawabannya. Template adalah alat khusus untuk kasus reset yang disengaja, bukan pengganti layout sehari-hari.

Tantangan

Buktikan bedanya

Buat dua versi: satu section memakai layout berisi counter, satu memakai template berisi counter. Navigasi antar halaman dalam section masing-masing dan catat mana yang reset.