React Custom Hooks: Reutiliza tu lógica
Aprende a crear custom hooks poderosos para compartir lógica entre componentes
React Custom Hooks: Reutiliza tu lógica
Los custom hooks te permiten extraer lógica de componentes en funciones reutilizables, haciendo tu código más limpio y mantenible.
Tu primer custom hook: useFetch
import { useState, useEffect } from 'react';
function useFetch(url) {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch(url);
const json = await response.json();
setData(json);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
}
// Uso
function UserProfile({ userId }) {
const { data, loading, error } = useFetch(`/api/users/${userId}`);
if (loading) return <p>Cargando...</p>;
if (error) return <p>Error: {error.message}</p>;
return <div>{data.name}</div>;
}
useLocalStorage: Persistencia simple
import { useState, useEffect } from 'react';
function useLocalStorage(key, initialValue) {
const [value, setValue] = useState(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
console.error(error);
return initialValue;
}
});
useEffect(() => {
try {
window.localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error(error);
}
}, [key, value]);
return [value, setValue];
}
// Uso
function Settings() {
const [theme, setTheme] = useLocalStorage('theme', 'light');
return (
<button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
Tema actual: {theme}
</button>
);
}
useDebounce: Optimiza búsquedas
import { useState, useEffect } from 'react';
function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}
// Uso
function SearchBar() {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearchTerm = useDebounce(searchTerm, 500);
useEffect(() => {
if (debouncedSearchTerm) {
// Hacer búsqueda solo después de 500ms de inactividad
console.log('Buscando:', debouncedSearchTerm);
}
}, [debouncedSearchTerm]);
return (
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Buscar..."
/>
);
}
useWindowSize: Responsive hooks
import { useState, useEffect } from 'react';
function useWindowSize() {
const [windowSize, setWindowSize] = useState({
width: undefined,
height: undefined,
});
useEffect(() => {
function handleResize() {
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
window.addEventListener('resize', handleResize);
handleResize();
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowSize;
}
// Uso
function ResponsiveComponent() {
const { width } = useWindowSize();
return (
<div>
{width < 768 ? (
<MobileLayout />
) : (
<DesktopLayout />
)}
</div>
);
}
useToggle: Booleanos simplificados
import { useState } from 'react';
function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = () => setValue(prev => !prev);
const setTrue = () => setValue(true);
const setFalse = () => setValue(false);
return [value, { toggle, setTrue, setFalse }];
}
// Uso
function Modal() {
const [isOpen, { toggle, setFalse }] = useToggle();
return (
<>
<button onClick={toggle}>Abrir Modal</button>
{isOpen && (
<div className="modal">
<p>Contenido del modal</p>
<button onClick={setFalse}>Cerrar</button>
</div>
)}
</>
);
}
usePrevious: Acceder al valor anterior
import { useRef, useEffect } from 'react';
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
// Uso
function Counter() {
const [count, setCount] = useState(0);
const prevCount = usePrevious(count);
return (
<div>
<p>Ahora: {count}</p>
<p>Antes: {prevCount}</p>
<button onClick={() => setCount(count + 1)}>Incrementar</button>
</div>
);
}
useForm: Manejo de formularios
import { useState } from 'react';
function useForm(initialValues) {
const [values, setValues] = useState(initialValues);
const handleChange = (e) => {
const { name, value } = e.target;
setValues(prev => ({
...prev,
[name]: value
}));
};
const reset = () => setValues(initialValues);
return { values, handleChange, reset };
}
// Uso
function LoginForm() {
const { values, handleChange, reset } = useForm({
email: '',
password: ''
});
const handleSubmit = (e) => {
e.preventDefault();
console.log(values);
reset();
};
return (
<form onSubmit={handleSubmit}>
<input
name="email"
value={values.email}
onChange={handleChange}
/>
<input
name="password"
type="password"
value={values.password}
onChange={handleChange}
/>
<button type="submit">Iniciar sesión</button>
</form>
);
}
Reglas de los Custom Hooks
- Siempre comienza con "use":
useNombreDescriptivo - Sigue las reglas de hooks: Solo llamar en el nivel superior
- Mantén la independencia: No dependas de contexto externo innecesario
- Documenta bien: Especialmente los parámetros y valores de retorno
Conclusión
Los custom hooks son una herramienta fundamental para crear aplicaciones React mantenibles. Te permiten compartir lógica compleja de manera simple y declarativa.
CodeCraft Master
Desarrollador Full Stack apasionado por compartir conocimiento. Escribo sobre JavaScript, TypeScript, React y desarrollo web moderno.
Artículos Relacionados
ReactIntroducción a React Hooks: useState y useEffect
Aprende los fundamentos de los hooks más utilizados en React y cómo pueden simplificar tu código
ReactReact Context API: Estado global sin Redux
Aprende a manejar estado global en React usando Context API, una alternativa más simple a Redux
Únete a nuestro boletín
Recibe contenido exclusivo de desarrollo web directamente en tu bandeja de entrada.
Contenido exclusivo de desarrollo web
Actualizaciones semanales
Tips y trucos
Sin spam, solo contenido de calidad