💻 Exemplos: Capítulo 06: Acesso ao DOM e Valores Persistentes com useRef e useId
Especialização Frontend com React & TypeScript • Demonstrações Práticas Executáveis
🎯 Contexto e Objetivo Prático
Manipulação imperativa de foco com useRef tipado e geração determinística de IDs acessíveis para leitores de tela com useId.
💻 Código Fonte React 19 (TSX)
// SearchBarAccessible.tsx
import React, { useRef, useId } from "react";
export function AccessibleSearchBar({ onSearch }: { onSearch: (term: string) => void }) {
// 1. useId: IDs únicos e sincronizados entre SSR e Hydration
const inputId = useId();
const descriptionId = useId();
// 2. useRef: Referência fortemente tipada ao elemento HTML nativo
const inputRef = useRef<HTMLInputElement>(null);
const handleClearAndFocus = () => {
if (inputRef.current) {
inputRef.current.value = "";
inputRef.current.focus(); // Manipulação imperativa segura
}
};
const handleFormSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (inputRef.current) {
onSearch(inputRef.current.value);
}
};
return (
<form onSubmit={handleFormSubmit} className="space-y-2 max-w-sm">
<label htmlFor={inputId} className="block text-sm font-medium text-slate-700">
Buscar no Repositório:
</label>
<div className="flex gap-2">
<input
id={inputId}
ref={inputRef}
type="search"
aria-describedby={descriptionId}
placeholder="Digite um termo..."
className="flex-1 px-3 py-2 border rounded-lg text-sm focus:ring-2 focus:ring-blue-500"
/>
<button
type="button"
onClick={handleClearAndFocus}
className="px-3 py-2 bg-slate-100 hover:bg-slate-200 text-xs rounded-lg"
>
Limpar
</button>
</div>
<p id={descriptionId} className="text-xs text-slate-500">
Pressione Enter para confirmar a busca por cursos ou tópicos.
</p>
</form>
);
}
🖥️ Saída de Renderização Visual e Comportamento
[Campo Acessível Renderizado]
Label for="«r1»" -> Input id="«r1»" aria-describedby="«r2»"
Texto auxiliar id="«r2»"
(Foco automático aplicado via inputRef.current.focus() sem re-render)