Patrones practicos
Fetch con async/await
function Users() {
const [users, setUsers] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
// No puedes hacer useEffect async directamente
// Crea una funcion async dentro
const fetchUsers = async () => {
try {
setLoading(true);
const res = await fetch('/api/users');
if (!res.ok) throw new Error('Error al cargar');
const data = await res.json();
setUsers(data);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchUsers();
}, []);
if (loading) return <p>Cargando...</p>;
if (error) return <p>Error: {error}</p>;
return (
<ul>
{users.map(u => <li key={u.id}>{u.name}</li>)}
</ul>
);
}
Debounce de busqueda
function Search() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
useEffect(() => {
if (!query) {
setResults([]);
return;
}
// Espera 300ms antes de buscar
const timer = setTimeout(() => {
fetch(`/api/search?q=${query}`)
.then(res => res.json())
.then(setResults);
}, 300);
return () => clearTimeout(timer);
}, [query]);
return (
<div>
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Buscar..."
/>
<ul>
{results.map(r => <li key={r.id}>{r.title}</li>)}
</ul>
</div>
);
}
Local Storage
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
const saved = localStorage.getItem(key);
return saved ? JSON.parse(saved) : initialValue;
});
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
}
// Uso
function App() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
return (
<button onClick={() => setTheme(t => t === 'light' ? 'dark' : 'light')}>
Tema: {theme}
</button>
);
}
Evitar efectos innecesarios
// MAL - efecto innecesario
function Form() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);
}
// BIEN - calcula durante el render
function Form() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
// Derivado, no necesita estado
const fullName = firstName + ' ' + lastName;
}