Cara mengatasi window is not defined Next.js paling cepat adalah memindahkan akses window dari render server ke kode yang hanya jalan di browser. Bungkus dengan guard typeof window !== "undefined", pindahkan ke useEffect atau event handler, dan jadikan komponen tersebut Client Component.
Penyebab Window Is Not Defined di App Router
App Router merender Server Component di server secara default. Objek window, document, dan localStorage hanya ada di browser, jadi kode langsung error saat prerender atau SSR.
- Akses langsung di body komponen, contohnya
const w = window.innerWidth. - State awal memakai browser API, contohnya
useState(localStorage.getItem("theme")). - Import library chart, map, atau editor yang membaca
windowsaat modul dimuat. - Script third-party dipanggil tanpa menunggu komponen ter-mount di browser.
Tabel Diagnosis Cepat Window Is Not Defined
| Masalah | Penyebab | Solusi |
|---|---|---|
| Error di Server Component | Akses window saat render server |
Pindah ke Client Component plus guard browser |
Error dari localStorage |
Dibaca sebelum mount | Baca di useEffect lalu simpan ke state |
| Error dari library chart/map | Library membaca DOM saat import | Gunakan dynamic import dengan ssr: false |
| Error hanya di build | Halaman di-prerender | Tunda akses browser sampai efek client berjalan |
- Periksa stack trace untuk menemukan nama file dan nomor baris.
- Curigai event handler yang memanggil fungsi browser selama render.
- Curigai
useEffectyang tertinggal di Server Component.
Cara Memperbaiki Window Is Not Defined dengan Aman
- Temukan baris error dari pesan build atau dev overlay.
- Tentukan apakah kode memang butuh browser. Jika ya, tambahkan
"use client"di baris pertama file. - Bungkus akses langsung dengan guard browser.
- Pindahkan pembacaan awal ke
useEffectdan simpan hasilnya di state. - Untuk library browser-only, muat dengan dynamic import dan matikan SSR.
Guard minimal:
if (typeof window !== "undefined") {
const width = window.innerWidth;
}
Pola useEffect:
"use client";
import { useEffect, useState } from "react";
export default function ThemeLabel() {
const [theme, setTheme] = useState("light");
useEffect(() => {
setTheme(localStorage.getItem("theme") ?? "light");
}, []);
return <p>{theme}</p>;
}
Dynamic import untuk komponen browser-only:
import dynamic from "next/dynamic";
const MapView = dynamic(() => import("./MapView"), { ssr: false });
Menambah "use client" tanpa guard belum aman karena Client Component tetap dirender sekali di server.
FAQ
Apakah semua kode window harus masuk useEffect?
Tidak. Event handler boleh memakai window langsung karena hanya jalan setelah klik atau interaksi browser.
Kapan memakai dynamic import dengan ssr false?
Pakai saat library membaca window atau DOM sejak proses import, seperti peta dan sebagian chart interaktif.
Mengapa localStorage ikut memicu error yang sama?
localStorage juga API browser, sehingga pembacaannya harus menunggu kode berjalan di client.