Cara Membuat Custom Hook Next Js yang Aman Dipakai di Client Component

Cara membuat custom hook Next.js yang aman adalah menulis fungsi use… berisi useState dan useEffect, lalu memakainya hanya dari Client Component dengan use client. Langkah yang sering terlewat adalah membungkus pemakaian hook dengan komponen client ketika halaman induknya Server Component. Tanpa pembungkus itu, build langsung gagal karena hook dipanggil di server.

Aturan Wajib Custom Hook di App Router

Custom hook tetap mengikuti aturan React Hooks. Next.js App Router menambah batas server dan client.

  • Hook hanya berjalan di Client Component. File komponen pemakai wajib diawali use client.
  • Nama hook diawali use, misalnya useCounter atau useLocalStorage.
  • Panggil hook di level atas fungsi, bukan di dalam kondisi, loop, atau fungsi nested.
  • Jadikan custom hook bila ada state, efek, atau browser API yang dipakai ulang di beberapa komponen.

Langkah Membuat Custom Hook Next Js

Ikuti urutan ini supaya tidak menabrak Server Component.

  1. Buat Client Component pembungkus bila halaman memakai Server Component. Halaman tetap server, bagian interaktif dipindah ke komponen client.
  2. Tulis file hook, contoh hooks/useCounter.ts. Isi dengan logika murni React.
import { useState } from "react";

export function useCounter(initial = 0) {
  const [count, setCount] = useState(initial);
  const increment = () => setCount((c) => c + 1);
  const decrement = () => setCount((c) => c - 1);
  return { count, increment, decrement };
}

3. Kelola useState dan useEffect di dalam hook. Jangan membaca window saat render awal.

4. Return value yang kecil dan jelas. Objek dengan dua sampai empat field lebih mudah dipakai ulang.

5. Pakai hook di beberapa komponen client. Setiap komponen mendapat state sendiri.

"use client";
import { useCounter } from "./hooks/useCounter";

export default function CounterBox() {
  const { count, increment } = useCounter(0);
  return <button onClick={increment}>Klik: {count}</button>;
}

Contoh Custom Hook untuk Fetch dan Browser API

Contoh useFetch menangani loading dan error tanpa library tambahan.

import { useEffect, useState } from "react";

export function useFetch(url: string) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    let active = true;
    fetch(url)
      .then((res) => {
        if (!res.ok) throw new Error("Gagal memuat data");
        return res.json();
      })
      .then((json) => active && setData(json))
      .catch((err) => active && setError(err))
      .finally(() => active && setLoading(false));
    return () => { active = false; };
  }, [url]);

  return { data, loading, error };
}

Contoh useLocalStorage aman dari window is not defined karena akses storage terjadi di efek.

  • Kode valid dan minimal tanpa dependency tambahan.
  • State awal memakai nilai default, bukan langsung membaca localStorage.
  • Pembacaan dan penulisan storage dilakukan setelah komponen mount di browser.

Kesalahan Umum dan Cara Memperbaikinya

Masalah Penyebab Solusi
Hook dipanggil dari Server Component Komponen pemakai tanpa use client Pindah pemakaian ke Client Component
Hydration mismatch Render server dan client beda karena localStorage Render nilai default dulu, sinkronkan di useEffect
Infinite loop fetch Dependency useEffect berubah tiap render Stabilkan URL dan dependency, cek array deps

Jangan hanya menaruh use client di file hook. React memeriksa komponen yang memanggil hook, bukan file tempat hook didefinisikan.

FAQ

Apakah custom hook bisa dipakai di Server Component?

Tidak. Server Component tidak mendukung useState, useEffect, atau hook lain.

Di mana file custom hook sebaiknya disimpan?

Simpan di folder seperti app/hooks atau components/hooks agar mudah dipakai ulang.

Kenapa state custom hook tidak berbagi antar komponen?

Setiap panggilan hook membuat state baru. Gunakan context atau state global bila perlu berbagi data.