Los Hooks se definen mediante funciones JavaScript. Representan un tipo especial de lógica de UI reutilizable, con ciertas restricciones acerca de dónde pueden ser llamados.


Sólo llama a los Hooks en el nivel más alto

En React, las funciones cuyos nombres empiezan con use son llamadas Hooks.

No llames a los Hooks dentro de bucles, condicionales, funciones anidadas o bloques try/catch/finally. En su lugar, utilízalos siempre en el nivel más alto de tu función React, antes de cualquier retorno anticipado. Sólo puedes llamar a los Hooks mientras React esté renderizando un componente funcional:

function Counter() {
// ✅ Bien: nivel más alto en un componente funcional
const [count, setCount] = useState(0);
// ...
}

function useWindowWidth() {
// ✅ Bien: nivel más alto en un custom Hook
const [width, setWidth] = useState(window.innerWidth);
// ...
}

No se admite llamar a los Hooks (funciones que empiezan con use) en casos como por ejemplo:

  • 🔴 No llamar a los Hooks dentro de condicionales o bucles.
  • 🔴 No llamar a los Hooks después de una declaración return condicional.
  • 🔴 No llamar a los Hooks dentro de event handlers.
  • 🔴 No llamar a los Hooks dentro de componentes de clase.
  • 🔴 No llamar a los Hooks dentro de funciones pasadas a useMemo, useReducer o useEffect.
  • 🔴 No llamar a los Hooks dentro de bloques try/catch/finally.

Si rompes estas reglas, es posible que veas este error.

function Bad({ cond }) {
if (cond) {
// 🔴 Mal: Hook llamado dentro de una condición (solución, muévelo afuera de la condición!)
const theme = useContext(ThemeContext);
}
// ...
}

function Bad() {
for (let i = 0; i < 10; i++) {
// 🔴 Mal: Hook llamado dentro de un bucle (solución, muévelo afuera del bucle!)
const theme = useContext(ThemeContext);
}
// ...
}

function Bad({ cond }) {
if (cond) {
return;
}
// 🔴 Mal: Hook llamado después de una condición de retorno (solución, muévelo antes del return!)
const theme = useContext(ThemeContext);
// ...
}

function Bad() {
function handleClick() {
// 🔴 Mal: Hook llamado dentro de una función event handler (solución, muévelo afuera de la función event handler!)
const theme = useContext(ThemeContext);
}
// ...
}

function Bad() {
const style = useMemo(() => {
// 🔴 Mal: Hook llamado dentro de un useMemo (solución, muévelo afuera de la función useMemo!)
const theme = useContext(ThemeContext);
return createStyle(theme);
});
// ...
}

class Bad extends React.Component {
render() {
// 🔴 Mal: Hook llamado dentro de un componente de clase (solución, escribe un componente funcional en vez de un componente de clase!)
useEffect(() => {})
// ...
}
}

function Bad() {
try {
// 🔴 Bad: Hook llamado dentro de un bloque try/catch/finally (solución, muévelo afuera del bloque!)
const [x, setX] = useState(0);
} catch {
const [x, setX] = useState(1);
}
}

Puedes usar el eslint-plugin-react-hooks plugin, para capturar estos errores.

Nota

Es posible que los Custom Hooks llamen a otros Hooks (ése es su propósito). Esto funciona porque se supone que los custom Hooks sean también llamados, sólo mientras se renderiza un componente funcional.


Sólo llama a los Hooks desde funciones React

No llames a los Hooks desde funciones convencionales de JavaScript. En su lugar, puedes:

✅ Llamar a los Hooks desde componentes funcionales de React. ✅ Llamar a los Hooks desde otros custom Hooks.

Al seguir esta regla, nos aseguramos que toda la lógica del estado de un componente, sea claramente visible desde su código fuente.

function FriendList() {
const [onlineStatus, setOnlineStatus] = useOnlineStatus(); // ✅
}

function setOnlineStatus() { // ❌ No es ni un componente ni un custom Hook!
const [onlineStatus, setOnlineStatus] = useOnlineStatus();
}