Jangan Diakses dari Server: Cara Mengakses LocalStorage Next Js

Cara mengakses localStorage Next.js yang benar adalah membacanya hanya di Client Component setelah mount. Server Component tidak punya objek window, jadi pemanggilan langsung memicu error. Tunda pembacaan memakai useEffect dan siapkan nilai awal agar render server dan klien tetap sama.

Kenapa localStorage Error di App Router

App Router merender Server Component di server Node.js. Lingkungan itu tidak menyediakan API browser, termasuk localStorage.

Masalah kedua adalah hydration mismatch. Server mengirim HTML dengan nilai default, lalu klien merender nilai berbeda dari localStorage. React mendeteksi perbedaan itu dan gagal melakukan hydration.

Pola amannya sederhana. Render dulu dengan nilai awal yang konsisten, lalu baca localStorage setelah komponen terpasang lewat useEffect.

Cara Mengakses LocalStorage Next Js dengan Aman

Ikuti urutan ini di Client Component:

  1. Tambahkan “use client” di baris pertama file.
  2. Buat state dengan nilai awal, misalnya tema terang.
  3. Baca localStorage di dalam useEffect dengan guard typeof window.
  4. Simpan hasil bacaan ke state.
  5. Tulis kembali ke localStorage setiap state berubah.
"use client";
import { useEffect, useState } from "react";

export default function ThemeToggle() {
  const [theme, setTheme] = useState("light");

  useEffect(() => {
    const saved = localStorage.getItem("theme");
    if (saved) setTheme(saved);
  }, []);

  useEffect(() => {
    localStorage.setItem("theme", theme);
  }, [theme]);

  return (
    <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
      Tema: {theme}
    </button>
  );
}

Periksa tiga hal ini sebelum menyimpan:

  • File memakai penanda Client Component.
  • Setiap akses langsung dibungkus pengecekan browser.
  • State punya nilai awal yang sama untuk server dan klien.

Tabel Troubleshooting localStorage

Masalah Penyebab Solusi
window is not defined Kode berjalan di Server Component Pindah ke Client Component dan baca di useEffect
Null saat render awal State dibaca sebelum browser siap Pakai nilai awal lalu perbarui setelah mount
Hydration failed Output server dan klien berbeda Render konsisten dulu, sinkronkan localStorage belakangan

Contoh Custom Hook useLocalStorage

Hook ini membaca sekali saat mount, lalu menyediakan setter yang otomatis sinkron ke browser. Pola ini cocok untuk tema, bahasa, status sidebar, dan token non sensitif.

"use client";
import { useEffect, useState } from "react";

export function useLocalStorage(key, initialValue) {
  const [value, setValue] = useState(initialValue);

  useEffect(() => {
    const saved = localStorage.getItem(key);
    if (saved !== null) setValue(JSON.parse(saved));
  }, [key]);

  const setStoredValue = (next) => {
    setValue(next);
    localStorage.setItem(key, JSON.stringify(next));
  };

  return [value, setStoredValue];
}

Jangan simpan JWT rahasia, refresh token, atau password di localStorage karena JavaScript lain bisa membacanya lewat XSS. Data sensitif lebih aman di cookie httpOnly yang dikelola server.

FAQ

Apakah Server Component bisa membaca localStorage Next Js?

Tidak bisa karena Server Component berjalan di server tanpa API browser.

Kenapa localStorage bernilai null saat pertama render?

Nilai belum tersedia sebelum efek klien berjalan, jadi komponen memakai nilai awal terlebih dahulu.

Apakah localStorage cocok untuk token login?

Tidak cocok untuk token sensitif karena rentan dicuri lewat XSS.