¿Qué problema resuelven los HOC?
Imaginemos que tenemos tres componentes que necesitan datos de autenticación. Sin HOC, repetiríamos la lógica de autenticación en cada componente. Con un HOC, envolvemos cada componente y automáticamente obtienen acceso a la información de usuario.
Sintaxis básica de un HOC
La estructura fundamental de un HOC sigue este patrón:
const withHOC = (WrappedComponent) => {
return function(props) {
// Lógica adicional aquí
const nuevaProp = 'dato inyectado';
return ;
}
};
// Uso
const ComponenteMejorado = withHOC(ComponenteOriginal);
with. Así withAuth, withTheme, withData comunican inmediatamente su propósito.HOC con Estado y Efectos
El verdadero poder de los HOC aparece cuando necesitamos compartir estado o lifecycle methods entre múltiples componentes:
import { useState, useEffect } from 'react';
const withMouseTracker = (WrappedComponent) => {
return function ConMouseTracker(props) {
const [position, setPosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMouseMove = (e) => {
setPosition({ x: e.clientX, y: e.clientY });
};
window.addEventListener('mousemove', handleMouseMove);
return () => window.removeEventListener('mousemove', handleMouseMove);
}, []);
return (
);
};
};
// Componente que usa el HOC
const PanelEstadistico = ({ mousePosition, titulo }) => (
{titulo}
Posición del mouse: X={mousePosition.x}, Y={mousePosition.y}
);
const PanelMejorado = withMouseTracker(PanelEstadistico);
Pasos para crear un HOC robusto
- Identifica la lógica repetida: Busca código que copies entre componentes similares.
- Crea la función HOC: Debe recibir el componente y retornar uno nuevo con las props adicionales.
- Pasa las props correctamente: Usa el spread operator para mantener las props originales.
- Considera las props omitidas: Si el HOC consume props internas,文档它们 en el nombre o propTypes.
- Agrega displayName: Facilita el debugging en React DevTools.
HOC con Múltiples Parámetros
Los HOC pueden recibir parámetros adicionales para configurarlos dinámicamente:
const withAuth = (WrappedComponent, opciones = {}) => {
const { requiereAdmin = false } = opciones;
return function ConAuth(props) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
verificarAuth().then((userData) => {
setUser(userData);
setLoading(false);
});
}, []);
if (loading) return Cargando...;
if (requiereAdmin && !user?.esAdmin) {
return Acceso denegado;
}
return ;
};
};
// Uso con configuración
const DashboardAdmin = withAuth(Dashboard, { requiereAdmin: true })(Dashboard);
Display Name para Debugging
En React DevTools, los componentes HOC pueden aparecer sin nombre. Corrige esto:
const withData = (WrappedComponent) => {
function ConData(props) {
// lógica...
return ;
}
ConData.displayName = `withData(${WrappedComponent.displayName || WrappedComponent.name || 'Component'})`;
return ConData;
};
HOC vs Render Props vs Hooks
| Criterio | HOC | Render Props | Hooks |
|---|---|---|---|
| Reutilización | Excelente | Buena | Excelente |
| Complejidad | Media | Baja | Baja |
| Props naming | Puede冲突 | Control total | Control total |
| Estilo dominante | Clásico | Legacy | Moderno |
HOC Real: withLoading
Un HOC práctico que muestra estados de carga:
const withLoading = (WrappedComponent) => { return function ConLoading({ isLoading, error, ...props }) { if (error) { return (); } if (isLoading) { return (Error al cargar
{error.message}
window.location.reload()}>Reintentar); } return ; }; }; // Componente limpio const ListaUsuarios = ({ usuarios }) => (Cargando...
{usuarios.map(u =>
); // Envuelto con loading const ListaUsuariosConLoading = withLoading(ListaUsuarios); // Uso: automáticamente maneja loading y error <ListaUsuariosConLoading isLoading={cargando} error={error} usuarios={usuarios} />- {u.nombre}
)}
Los HOC son como礼服 a la medida: envuelven tu componente existente con nuevas capacidades sin alterar el traje original.
Composición de HOC
Puedes encadenar múltiples HOC para combinar funcionalidades:
const App = withAuth(
withTheme(
withLoading(
Dashboard
)
)
);
// O con composición:
const compose = (...hocs) => (Component) =>
hocs.reduce((acc, hoc) => hoc(acc), Component);
const App = compose(
withAuth,
withTheme,
withLoading
)(Dashboard);
compose viene de librerías como Redux (connect) y Lodash (flow). Hace el código más legible cuando tienes muchos HOC.Cosas a Evitar
Ver más- No modifiques el componente original: No uses
React.cloneElementparamutarlo. - No uses refs en props: Las refs no se pasan como props normales. Usa
forwardRefsi necesitas refs. - No copies props estáticas: Si el componente original tiene métodos estáticos, debes copiarlos manualmente.
// ❌ Incorrecto
const withEjemplo = (WrappedComponent) => {
return class extends React.Component {
render() {
const { exclude, ...props } = this.props;
return ;
}
};
};
// ✅ Correcto con forwardRef
const withEjemplo = (WrappedComponent) => {
function ConEjemplo(props, ref) {
return ;
}
return React.forwardRef(ConEjemplo);
};
Resumen Práctico
Los High Order Components siguen el principio de composición sobre herencia. Son ideales para:
- Compartir lógica de acceso a datos
- Inyectar props transversales (tema, auth, locale)
- Wrapper visuales (loading, error, wrapper de portal)
- Componentes con características comunes reutilizables
¿Cuál es la principal ventaja de usar HOC sobre copiar y pegar código en múltiples componentes?
- A) Los HOC hacen que el código sea más rápido
- B) Los HOC permiten compartir lógica sin modificar los componentes originales
- C) Los HOC eliminan la necesidad de props
- D) Los HOC son más fáciles de escribir que hooks
En la próxima lección exploraremos cómo los HOC se comparan con los Render Props y cuándo elegir cada patrón según el contexto de tu aplicación.