Watch-IP

Geolokasi IP di React: komponen lokasi pengunjung

Bangun hook useVisitorGeo yang bisa dipakai ulang di sekitar Watch-IP JavaScript SDK, dengan penanganan loading, error, dan cancellation yang dibutuhkan komponen React sungguhan — termasuk alasan mengapa request bisa terpicu dua kali dalam mode development.

Sebelum Anda mulai

  • Akun Watch-IP dan publishable visitor key dengan origin aplikasi Anda (dev dan production) ada di daftar allowed-origins-nya.
  • React 18 atau lebih baru — perilaku double-invoke StrictMode yang dijelaskan di bawah ini khusus untuk mode development.
  • @digitload/watch-ip-sdk terpasang (npm install @digitload/watch-ip-sdk).

1. Bangun hook useVisitorGeo

Bungkus pemanggilan getGeo() dari SDK dalam sebuah hook yang melacak status loading/result/error dan membatalkan request jika komponennya unmount sebelum request selesai.

TypeScript

import { useEffect, useState } from "react";
import { WatchIP, type GeoResponse } from "@digitload/watch-ip-sdk";

const client = new WatchIP("YOUR_PUBLISHABLE_KEY");

export function useVisitorGeo() {
  const [geo, setGeo] = useState<GeoResponse | null>(null);
  const [status, setStatus] = useState<"loading" | "ready" | "error">("loading");

  useEffect(() => {
    const controller = new AbortController();

    client
      .getGeo({ signal: controller.signal })
      .then((result) => {
        setGeo(result);
        setStatus("ready");
      })
      .catch((err) => {
        if (err.name !== "AbortError") setStatus("error");
      });

    return () => controller.abort();
  }, []);

  return { geo, status };
}

2. Mengapa request bisa terpicu dua kali dalam development

React StrictMode secara sengaja me-mount, unmount, lalu me-remount setiap komponen satu kali dalam mode development untuk memunculkan efek yang tidak membersihkan dirinya sendiri. Artinya efek hook ini berjalan dua kali, dan AbortController di atas jadi penting: request pertama dibatalkan oleh fungsi cleanup sebelum selesai, sehingga hanya satu panggilan getGeo() sungguhan yang benar-benar selesai. Melewatkan pemanggilan abort tidak akan merusak kebenarannya — GET /v1/geo adalah operasi baca — tapi akan meninggalkan request in-flight yang redundan dan pembaruan state yang tidak pernah digunakan oleh instance pertama yang dibuang.

3. Render kondisi loading, hasil, dan fallback

Gunakan hook ini seperti Anda menggunakan hook data lainnya, jaga agar default yang masuk akal tetap terlihat sampai status keluar dari 'loading'.

TypeScript (JSX)

function RegionBanner() {
  const { geo, status } = useVisitorGeo();

  if (status === "loading") return <p>Mendeteksi wilayah Anda…</p>;
  if (status === "error" || !geo?.country) return <p>Menampilkan wilayah default</p>;
  return <p>Menampilkan konten untuk {geo.city ?? geo.country}</p>;
}

4. Pertahankan pilihan eksplisit pengunjung

Aturan yang sama seperti panduan JavaScript biasa: periksa dulu apakah ada preferensi yang tersimpan sebelum menerapkan country yang disarankan, dan hanya jatuh kembali ke hasil hook saat belum ada preferensi.

TypeScript

const preferred = localStorage.getItem("preferredCountry");
const country = preferred ?? geo?.country ?? "US";

Error dan kasus khusus

Origin yang tidak diizinkan gagal sebelum kode Anda melihat respons normal — tambahkan dulu URL dev dan production aplikasi Anda ke allowed origins key tersebut. Setiap field pada GeoResponse kecuali ip dan isEUCountry bersifat nullable, jadi status === 'ready' saja tidak cukup; periksa juga field spesifik yang akan Anda render, seperti yang dilakukan fallback di atas dengan geo?.country.

Langkah berikutnya

Menggunakan Next.js? Model server-rendering-nya mengubah di mana request ini bisa berjalan dengan aman — lihat panduan Next.js untuk pembagian client/server dan pola server secret-key untuk IP yang dikirim.

Halaman terkait