URL States: guardando dados do usuário na URL em NextJS (App Dir)

ReactJS • 🗓️ 5 de outubro de 2023 • ☕ 5 min(s) de leitura

É muito comum em frameworks como React guardar o estado do usuário em hooks como useState. E isso é ótimo, pois é simples e rápido. Porém, às vezes, é interessante permitir ao usuário manter esse usuário salvo e compartilhável, isto é, permitir que ele possa salvar o que ele estava fazendo e até mesmo compartilhar isso com outros usuários.

O interessante de manter o estado salvo na URL é que é possível fazer tudo isso. Um exemplo é quando você quer mostrar uma pesquisa no Google para algum amigo: basta copiar a URL e ele verá o mesmo que você (ou deveria…).

Vale destacar que o uso de URL States não deve ser generalizado - pelo contrário, deve ser usado somente quando seu uso se justifica. Ou seja, se aquele estado é algo que faz sentido ser compartilhado. Um exemplo de uso são query de pesquisas e filtros em dashboards.

Criando um hook

Antes de mais anda, vale deixar claro que você não precisa de um hook para lidar com isso. Porém, eu resolvi criar um para me ajudar. Se você quiser, pode copiar o código e usar onde quiser.

O código do hook foi baseado na solução de commerce da vercel. Na versão deles, quando o usuário pesquisa algo, a informação é tratada como um estado de URL.

"use client";

import { usePathname, useRouter, useSearchParams } from "next/navigation";
import { useEffect, useState } from "react";

export default function useQueryState(key: string, defaultValue: string = "") {
  const router = useRouter();
  const searchParams = useSearchParams();
  const pathname = usePathname();

  const [value, setValue] = useState(searchParams.get(key) ?? defaultValue);

  useEffect(() => {
    const newParams = new URLSearchParams(searchParams.toString());

    newParams.set(key, value);

    if (!value) newParams.delete(key);

    router.replace(`${pathname}?${newParams.toString()}`);
  }, [key, pathname, router, searchParams, value]);

  return [value, setValue] as const;
}

O código acima funciona basicamente como um useState, porém com algumas diferenças. Ele recebe uma key e um valor inicial. A key é como ele irá aparecer na URL, por exemplo, se sua key for “query”, então sua URL será “seusite.com/blog?query=valor”.

Um exemplo de como usar:

// define os estado individualmente
// ambos irão aparecer na url
const [search, setSearch] = useQueryState("search");
const [tag, setTag] = useQueryState("tag");

return (
	<input
    type="text"
    placeholder="Ex: abacaxi"
    defaultValue={search}
    onChange={(event) => {
        setSearch(event.target.value);
    }}
  />
)

Se quiser ver um exemplo de como ele funciona, pode usar o campo de pesquisa e filtro do meu blog.

 
Um obrigado ao comentário do EdsonFerreira pelas dicas/sugestões!