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.tsx | template.tsx | |
|---|---|---|
| Di-render ulang saat navigasi? | Tidak | Ya |
| State di dalamnya bertahan? | Ya | Tidak, mount ulang dari nol |
| Effect jalan ulang? | Tidak | Ya |
| Cocok untuk | UI persisten | Reset 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:
// 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>
);
}// 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:
// 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. Pakaitemplate.tsxhanya 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.