High Order Components: Envolviendo Funcionalidad

Lectura
25 min~6 min lectura
CONCEPTO CLAVE: Un High Order Component (HOC) es una función que recibe un componente y devuelve un nuevo componente con funcionalidad adicional. No es un componente en sí mismo, sino un patrón que envuelve otros componentes para compartir lógica.

¿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.

📌 Regla de oro: Los HOC nunca deben modificar el componente original. Solo lo envuelven y le pasan props adicionales.

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);
💡 Tip profesional: Por convención, los HOC deben empezar con 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);
⚠️ Advertencia importante: Cuando uses HOC con hooks, recuerda que el HOC debe ser una función que retorna un componente funcional. No intentes usar hooks directamente en el HOC sin envolverlos en un componente funcional.

Pasos para crear un HOC robusto

  1. Identifica la lógica repetida: Busca código que copies entre componentes similares.
  2. Crea la función HOC: Debe recibir el componente y retornar uno nuevo con las props adicionales.
  3. Pasa las props correctamente: Usa el spread operator para mantener las props originales.
  4. Considera las props omitidas: Si el HOC consume props internas,文档它们 en el nombre o propTypes.
  5. 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);
📌 Esta técnica de doble invocación se llama currying y permite configuraciones flexibles.

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;
};
💡 Sin displayName, verás solo "ConData" en DevTools, lo que dificulta identificar qué componente es cada uno.

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
⚠️ Nota de transición: En proyectos nuevos, los hooks suelen ser preferidos. Sin embargo, entender HOC es esencial para mantener código legacy y frameworks como Redux connect().

HOC Real: withLoading

Un HOC práctico que muestra estados de carga:

const withLoading = (WrappedComponent) => {
  return function ConLoading({ isLoading, error, ...props }) {
    if (error) {
      return (
        

Error al cargar

{error.message}

window.location.reload()}>Reintentar
); } if (isLoading) { return (

Cargando...

); } return ; }; }; // Componente limpio const ListaUsuarios = ({ usuarios }) => (
    {usuarios.map(u =>
  • {u.nombre}
  • )}
); // Envuelto con loading const ListaUsuariosConLoading = withLoading(ListaUsuarios); // Uso: automáticamente maneja loading y error <ListaUsuariosConLoading isLoading={cargando} error={error} usuarios={usuarios} />
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);
💡 Esta técnica de 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.cloneElement paramutarlo.
  • No uses refs en props: Las refs no se pasan como props normales. Usa forwardRef si 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
📌 Recuerda: Los HOC añaden componentes extra al árbol de React. En rendimiento crítico, considera hooks o memoización.
🧠 Quiz

¿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
✅ Respuesta correcta: B. Los HOC envuelven componentes existentes para compartir funcionalidad, manteniendo los componentes originales limpios y reutilizables.

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.