Watch-IP

Geolocalización de IP en React: un componente de ubicación del visitante

Crea un hook useVisitorGeo reutilizable alrededor del SDK de JavaScript de Watch-IP, con el manejo de carga, error y cancelación que necesita un componente real de React, incluyendo por qué la solicitud puede dispararse dos veces en desarrollo.

Antes de empezar

  • Una cuenta de Watch-IP y una clave de visitante publicable con el origen de tu app (desarrollo y producción) en su lista de orígenes permitidos.
  • React 18 o más reciente: el comportamiento de doble invocación de StrictMode descrito abajo es específico del modo de desarrollo.
  • @digitload/watch-ip-sdk instalado (npm install @digitload/watch-ip-sdk).

1. Crea un hook useVisitorGeo

Envuelve la llamada getGeo() del SDK en un hook que rastree el estado de carga/resultado/error y cancele la solicitud si el componente se desmonta antes de que se resuelva.

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. Por qué la solicitud puede dispararse dos veces en desarrollo

El StrictMode de React monta, desmonta y vuelve a montar intencionalmente cada componente una vez en desarrollo para exponer efectos que no se limpian a sí mismos. Eso significa que el efecto de este hook se ejecuta dos veces, y ahí es donde importa el AbortController de arriba: la primera solicitud se cancela mediante la función de limpieza antes de resolverse, así que en realidad solo se completa una llamada real a getGeo(). Omitir la llamada de cancelación no rompería la corrección — GET /v1/geo es de solo lectura — pero dejaría una solicitud redundante en curso y una actualización de estado que la primera instancia descartada nunca llega a usar.

3. Renderiza los estados de carga, resultado y alternativa

Usa el hook igual que usarías cualquier otro hook de datos, manteniendo visible un valor predeterminado razonable hasta que status deje de ser 'loading'.

TypeScript (JSX)

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

  if (status === "loading") return <p>Detectando tu región…</p>;
  if (status === "error" || !geo?.country) return <p>Mostrando la región predeterminada</p>;
  return <p>Mostrando contenido para {geo.city ?? geo.country}</p>;
}

4. Preserva una elección explícita del visitante

Misma regla que la guía de JavaScript puro: comprueba si existe una preferencia almacenada antes de aplicar el país sugerido, y recurre al resultado del hook solo cuando todavía no exista ninguna preferencia.

TypeScript

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

Errores y casos límite

Un origen no permitido falla antes de que tu código vea una respuesta normal: añade primero las URL de desarrollo y producción de la app a los orígenes permitidos de la clave. Todos los campos de GeoResponse excepto ip e isEUCountry son anulables, así que status === 'ready' no basta por sí solo; comprueba también el campo específico que estás por renderizar, como hace arriba la alternativa con geo?.country.

Siguiente paso

¿Usas Next.js? Su modelo de renderizado en servidor cambia dónde puede ejecutarse de forma segura esta solicitud: consulta la guía de Next.js para conocer la separación entre cliente y servidor y un patrón de servidor con clave secreta para IP proporcionadas.

Páginas relacionadas