Watch-IP

IP-geolocatie in React: een bezoekerslocatiecomponent

Bouw een herbruikbare useVisitorGeo-hook rond de Watch-IP JavaScript SDK, met de laad-, fout- en annuleringsafhandeling die een echte React-component nodig heeft — inclusief waarom het verzoek in development twee keer kan worden verstuurd.

Voordat je begint

  • Een Watch-IP-account en een publiceerbare bezoekerssleutel met de origin van je app (dev en productie) op de lijst met toegestane origins.
  • React 18 of nieuwer — het dubbel-aanroepen-gedrag van StrictMode dat hieronder wordt beschreven, is specifiek voor development mode.
  • @digitload/watch-ip-sdk geïnstalleerd (npm install @digitload/watch-ip-sdk).

1. Een useVisitorGeo-hook bouwen

Wikkel de getGeo()-aanroep van de SDK in een hook die de laad-/resultaat-/fouttoestand bijhoudt en het verzoek annuleert als de component wordt unmount voordat het is afgerond.

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. Waarom het verzoek in development twee keer kan worden verstuurd

De StrictMode van React mount, unmount en remount elke component bewust één keer extra in development, om effecten te ontdekken die zichzelf niet opruimen. Dat betekent dat het effect van deze hook twee keer wordt uitgevoerd, en dan is de AbortController hierboven van belang: het eerste verzoek wordt geannuleerd door de cleanup-functie voordat het is afgerond, dus er wordt daadwerkelijk maar één echte getGeo()-aanroep voltooid. Het weglaten van de abort-aanroep zou de correctheid niet breken — GET /v1/geo is een leesactie — maar het zou wel een overbodig lopend verzoek achterlaten, en een statusupdate die de weggegooide eerste instantie nooit gebruikt.

3. Laad-, resultaat- en terugvaltoestanden renderen

Gebruik de hook op dezelfde manier als elke andere data-hook, en houd een zinvolle standaardwaarde zichtbaar totdat status niet meer 'loading' is.

TypeScript (JSX)

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

  if (status === "loading") return <p>Regio detecteren…</p>;
  if (status === "error" || !geo?.country) return <p>Standaardregio wordt getoond</p>;
  return <p>Inhoud tonen voor {geo.city ?? geo.country}</p>;
}

4. Een expliciete keuze van de bezoeker bewaren

Dezelfde regel als in de gewone-JavaScript-handleiding: controleer op een opgeslagen voorkeur voordat je het voorgestelde land toepast, en val alleen terug op het resultaat van de hook wanneer er nog geen voorkeur bestaat.

TypeScript

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

Foutmeldingen en randgevallen

Een niet-toegestane origin faalt voordat je code een normaal antwoord te zien krijgt — voeg eerst de dev- en productie-URL's van de app toe aan de toegestane origins van de sleutel. Elk veld op GeoResponse behalve ip en isEUCountry is nullable, dus status === 'ready' is op zichzelf niet genoeg; controleer ook het specifieke veld dat je gaat renderen, zoals de terugvaloptie hierboven doet met geo?.country.

Volgende stap

Gebruik je Next.js? Het server-rendering-model daarvan verandert waar dit verzoek veilig kan draaien — zie de Next.js-handleiding voor de client/server-splitsing en een server-patroon met geheime sleutel voor opgegeven IP's.

Gerelateerde pagina's