CodeForge

React 19 de Cero a Experto / Efectos y ciclo de vida

Custom hooks: empaqueta tu propia lógica

Teoría24 min20 XP

Fíjate en lo que se repite: el patrón de carga de datos, el de leer/escribir localStorage, el de un toggle. Copiar y pegar esa lógica en cada componente es justo lo que el SC-02 te enseñó a evitar. Los CUSTOM HOOKS son la respuesta de React: empaquetar lógica con estado y efectos en una función reutilizable que empieza por use. No es magia ni una API nueva —es una función normal que llama a otros hooks—. Hoy construyes los tuyos desde cero y entiendes por qué son el corazón de la reutilización en React.

Una receta que guardas y reúsas

Tu primer custom hook: useLocalStorage

Un hook propio es una función que empieza por use y USA otros hooks por dentro. Aquí encapsulamos "un estado que se persiste en localStorage":

useLocalStorage devuelve la misma tupla [valor, setValor] que useState —por eso se USA igual—, pero por dentro añade la persistencia con un efecto. Fíjate: lo llamas DOS veces (para nombre y para tema) y cada uno tiene su propio estado independiente. Un custom hook no comparte estado entre usos: cada llamada es una instancia fresca. Es genérico (<T>, SC-03), así que sirve para cualquier tipo. Escribiste la receta una vez; ahora persistir cualquier valor es una línea.

Las reglas de los hooks

Otro ejemplo: componer hooks

Los custom hooks se componen: uno puede usar a otro. Aquí useContador encapsula la lógica de un contador con límites, sin tocar el DOM ni saber nada de la UI:

use-contador.tsx
function useContador(inicial = 0, paso = 1) {
const [cuenta, setCuenta] = useState(inicial);

const incrementar = () => setCuenta((c) => c + paso);
const decrementar = () => setCuenta((c) => c - paso);
const reiniciar = () => setCuenta(inicial);

// devolvemos un objeto: la UI solo usa lo que le sirve
return { cuenta, incrementar, decrementar, reiniciar };
}

// en el componente:
function App() {
const { cuenta, incrementar, reiniciar } = useContador(0, 5);
return (
  <>
    <p>{cuenta}</p>
    <button onClick={incrementar}>+5</button>
    <button onClick={reiniciar}>Reiniciar</button>
  </>
);
}

useContador no sabe NADA de botones ni de estilos: solo expone estado (cuenta) y acciones (incrementar, etc.). El componente decide cómo pintarlo. Esa separación —lógica en el hook, UI en el componente— es lo que hace testeable y reutilizable tu código. Puedes usar useContador en diez pantallas distintas, cada una con su propio look.

¿Qué es exactamente un custom hook y qué lo distingue de una función normal?

Mini-reto

Construye dos hooks propios: 1) useToggle(inicial = false) que devuelva [valor, alternar] (usa useState y una función que haga setValor(v => !v)); úsalo para mostrar/ocultar un panel. 2) useAnterior(valor) que use un useRef y un useEffect para recordar el valor del render ANTERIOR (guarda valor en el ref DESPUÉS del render, y devuelve ref.current); muéstralo junto al valor actual. Confirma que ambos se usan como cualquier hook y que su lógica queda fuera del componente.

Qué sigue

Módulo 3 casi cerrado: dominas los efectos (y cuándo NO usarlos), useRef, la carga de datos y los custom hooks. El reto del módulo junta todo en una "Mi Bolsillo" que PERSISTE: tus gastos se guardan en localStorage con un custom hook y sobreviven a recargas —el mismo salto de "app con memoria" del SC-02, ahora en React declarativo—.