Cómo evitar la perforación de puntales con composición

Foto de rawpixel en Unsplash

React.js es uno de los frameworks front-end más populares. Es un excelente marco basado en componentes con una API declarativa que permite al desarrollador pensar en la interfaz de usuario como una función de estado y accesorios y no como una función del tiempo. En otras palabras, puede describir la apariencia de su Componente en función de los datos que se pasan.

La principal forma en que se transmiten los datos es mediante accesorios. En pocas palabras, los accesorios son los argumentos de las funciones que devuelven JSX. De hecho, la forma más simple de un componente es solo eso: una función de JavaScript.

const Header = props => {
    regreso(
         
            

{props.title}

         
    ); }

Los accesorios se pueden usar para varias cosas en el mismo componente. En el ejemplo anterior, lo estamos usando para configurar una clase css: oscura o clara. También se está utilizando para proporcionar los datos de la etiqueta del encabezado. Luego podemos usar el componente pasando los accesorios como atributos en nuestro JSX, de esta manera:

const App = props => {
    regreso(
         
                      
    ); }

Como puede ver, los accesorios pueden ser muy poderosos. Sin embargo, si se implementan de manera incorrecta, pueden ser muy difíciles de manejar. Uno de los mayores "No No’s" con accesorios es hacer lo que se llama "perforación de accesorios". La perforación de accesorios es cuando un accesorio se pasa a un Componente solo con el único propósito de pasarlo a un niño.

const Parent = ({className, title}) => {
    regreso(
         
            {...}                       
    ); }

En el ejemplo anterior, el título de propiedad se pasa al padre, pero el padre no lo usa más que para entregarlo al componente hijo. Esta no es una forma ideal de pasar datos. Digamos que nuestro componente hijo tiene otro accesorio que debemos aprovechar, ahora tenemos que pasar ese accesorio al componente padre solo para luego pasárselo al niño. A medida que pasa más tiempo y crece nuestra base de código, más propensos a errores serán nuestros datos y componentes. (Por cierto, en el ejemplo anterior, estoy aprovechando un operador ES6 llamado desestructuración, del que puede obtener más información en MDN)

A pesar del hecho de que sabemos evitarlo, la perforación de apoyo se arrastra silenciosamente sin que nos demos cuenta. Aquí hay un ejemplo de la vida real de un proyecto en el que estaba trabajando. Estaba trabajando en una sección de Héroe que tenía un título, un subtítulo y una lista de botones de "Llamado a la acción". Esto es con lo que comencé (lo simplifiqué para el ejemplo para que sea más fácil de leer):

const Hero = ({title, subtitle, ctas}) => {
    regreso(
         
             {title} 
             {subtitle} 
            
               {ctas.map (cta => )}
            
         
    );
}

El ejemplo anterior incluyó tres accesorios: título, subtítulo y una matriz de cta (llamada a la acción). El título y los subtítulos se colocan en sus componentes correspondientes y luego asignamos los ctas para obtener una matriz de LinkButtons. Esto es bastante simple de seguir y estaba funcionando muy bien.

Más tarde, me encontré con la necesidad de tener una fila de LinkButtons en otro lugar de mi aplicación. Afortunadamente, React hace que sea fácil reutilizar el código y reescribí la fila de botones de mi componente Hero para poder reutilizarlo en ambos lugares. Esto es lo que terminé con:

const ActionButtons = ({actions}) => {
    regreso(
       
          {actions.map (action => )}
       
    );
}
const Hero = ({title, subtitle, ctas}) => {
    regreso(
         
             {title} 
             {subtitle} 
            
         
    );
}

¿Viste lo que pasó? Ni siquiera me di cuenta al principio. Fue tan fácil refactorizar solo la parte que necesitaba que ni siquiera me di cuenta de que acababa de crear una situación de perforación de apoyo para mí. Estaba pasando un accesorio ctas al componente Hero solo para dar la vuelta y pasarlo a otro componente. Esto podría haber causado algunos dolores de cabeza importantes para mí más adelante y todo lo que estaba tratando de hacer era aprovechar la reutilización del código.

Afortunadamente, me sorprendí y refactoré el código de esta manera:

const Hero = ({title, subtitle, children}) => {
    regreso(
         
             {title} 
             {subtitle} 
            {niños}
         
    );
}

   

Como puede ver, ya no estoy representando explícitamente el componente ActionButtons en mi componente Hero. Simplemente estoy renderizando el accesorio para niños, que está disponible para cada componente React. Este patrón pone el control nuevamente en la mano de los desarrolladores para elegir qué y si representar algo allí. Luego paso el componente ActionButtons de niño al componente Hero. Esto me permite pasar los datos directamente al componente ActionButtons sin que el componente Hero incluso necesite saber nada sobre la API del componente ActionButtons.

El patrón de pasar componentes como hijos se llama "Composición". Es un patrón poderoso que permite tanto el desacoplamiento de componentes como la reutilización de código. Si desea obtener más información sobre la composición y cómo usarla, le recomiendo que consulte la página de inicio de React en Composición vs Herencia.

La ventaja que ahora tiene mi código es que a medida que el componente ActionButtons mejora y cambia, el Componente Hero no necesita saberlo. También le dio al Componente Hero más flexibilidad ya que ya no estaba acoplado al Componente ActionButtons, por lo que ahora puede mostrar lo que pueda necesitar allí o nada en absoluto. Mi código será mucho más fácil de mantener a medida que crezca mi base de código.