Watch-IP

Geolocalização de IP em React: um componente de localização do visitante

Construa um hook useVisitorGeo reutilizável em torno do SDK JavaScript do Watch-IP, com o tratamento de carregamento, erro e cancelamento de que um componente React real precisa — incluindo porque é que o pedido pode disparar duas vezes em desenvolvimento.

Antes de começar

  • Uma conta Watch-IP e uma chave de visitante publicável com a origem da sua aplicação (desenvolvimento e produção) na sua lista de origens permitidas.
  • React 18 ou mais recente — o comportamento de dupla invocação do StrictMode descrito abaixo é específico do modo de desenvolvimento.
  • @digitload/watch-ip-sdk instalado (npm install @digitload/watch-ip-sdk).

1. Construa um hook useVisitorGeo

Envolva a chamada getGeo() do SDK num hook que controla o estado de carregamento/resultado/erro e cancela o pedido se o componente for desmontado antes de ele ser resolvido.

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. Porque é que o pedido pode disparar duas vezes em desenvolvimento

O StrictMode do React monta, desmonta e volta a montar intencionalmente cada componente uma vez em desenvolvimento, para expor efeitos que não se limpam a si próprios. Isso significa que o efeito deste hook é executado duas vezes, e o AbortController acima é importante: o primeiro pedido é abortado pela função de limpeza antes de ser resolvido, pelo que apenas uma chamada real a getGeo() é efetivamente concluída. Ignorar a chamada de abort não comprometeria a correção — GET /v1/geo é uma leitura — mas deixaria um pedido em curso redundante e uma atualização de estado que a primeira instância descartada nunca utiliza.

3. Mostre os estados de carregamento, resultado e alternativa

Utilize o hook da mesma forma que utilizaria qualquer outro hook de dados, mantendo uma predefinição sensata visível até status deixar de ser 'loading'.

TypeScript (JSX)

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

  if (status === "loading") return <p>A detetar a sua região…</p>;
  if (status === "error" || !geo?.country) return <p>A mostrar a região predefinida</p>;
  return <p>A mostrar conteúdo para {geo.city ?? geo.country}</p>;
}

4. Preserve uma escolha explícita do visitante

Mesma regra do guia de JavaScript simples: verifique se existe uma preferência armazenada antes de aplicar o país sugerido, e só recorra ao resultado do hook quando ainda não existir preferência.

TypeScript

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

Erros e casos limite

Uma origem não permitida falha antes de o seu código ver uma resposta normal — adicione primeiro os URLs de desenvolvimento e produção da aplicação às origens permitidas da chave. Todos os campos de GeoResponse, exceto ip e isEUCountry, são anuláveis, pelo que status === 'ready' não é suficiente por si só; verifique também o campo específico que está prestes a apresentar, como a alternativa acima faz com geo?.country.

Próximo passo

Está a utilizar Next.js? O seu modelo de renderização no servidor altera onde este pedido pode ser executado com segurança — consulte o guia de Next.js para a divisão cliente/servidor e um padrão de servidor com chave secreta para IPs fornecidos.

Páginas relacionadas